2er0's Studio.

SWPUCTF_WriteUp

Word count: 2.1kReading time: 9 min
2020/12/06 Share

Web1

0x01 扫描目录加注入

拿到题目以为是注入,但是试了几次发现好像不太行,而且页面有点多,直接扫描目录

这一扫真不得了,居然这么多页面,我直接好家伙

挨个访问了一下,有用的只有那几个

clip_image002

先看看index.php.bak

1
2
3
4
5
6
7
8
9
GET /important_index_its_so_long_right.php?id=1 HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

明显是一个请求报文,这个url属实扎眼,可能存在注入。

Sqlmap直接爆破,有注入点,爆出h1nt和LTLT两个库,dump拿到用户名和密码。

clip_image004

password给的是md5值,直接在线解密(https://www.somd5.com/)

clip_image006

1
2
username:admin123
password:wllm@123

0x02登录

再到robots.txt里看一下,给了一个administrator.html,访问后用上面的用户名和密码登录

登录后发现还是没有什么可以突破的点

看了看源码又发现了一个奇怪的东西—writeuser_00001_log.log

clip_image008

里面放的是base64编码,挨个解密后发现了一个上传的php

clip_image010

/user:00001/time:10:27:23:16/ip:127.0.0.1/view:up_lo_ad_ad_min.php

又需要登录。但是不慌,回到原来那个数据库看看有没有密码

clip_image012

password:00001

登录成功,是个文件上传

0x03文件上传

随便上传了几个文件,发现只能上传图片类型的

抓包修改MIME,文件后缀,不行

又试了试 .htaccess文件不行,00截断也不行

无奈了

尝试访问了一下文件保存的路径,发现了一个2.php和3.php (猜测可能是哪位大师傅做题留下来的)

clip_image014

clip_image016

其中3.php还显示了phpinfo,猜测这两个都是别人上传到一句话木马,我们都知道一句话木马的密码都不会很长,而且一般很简单

cmd,123,111,a等

于是就直接爆这个一句话木马的木马,很快就试出来是 111,蚁剑链接拿到flag

clip_image018

Misc1

0X01

盲猜图片隐写,直接将马大师的动图拖进kali里面,binwalk -e盲猜图片隐写,直接将马大师的动图拖进kali里面,binwalk -e命令直接分离隐写内容,如图:

clip_image020

拿到mp4和flag.txt,心动一下,以为真是签到题,呵呵,小伙子还是太年轻了。

clip_image021

1
flag{Th1s_1s_fa1se_f1ag}``上来就分离我合成的``gif ``这好吗?这不好!

再去看MP4文件,一帧一帧的仔细欣赏闪电五连鞭法,背景里面发现一串字符,疑似base64,抄下来解码:

clip_image022

1
c2Inbl9pbg==` 解码得 : `sign_in

接下来没了思路,到处试,终于,kali binwalk -e分离mp4文件,得到压缩包,需要秘钥,刚好把刚才base64解码的字符串用上了,dedao19_20.txt文件,如图:

clip_image024

打开文件,一眼看去是base64编码,在线解码(https://www.qqxiuzi.cn/bianma/base.php)

GZBTONRXGU3DKNRZGYYTMQRXHA3TKNRUG4ZTOOJXGE3DKNRYG4ZTOQJXGE3DQNZZGZBDMNZWG43TGNZZG44TMQZWII3TMNZWGY4Q

base32解码:

6C76756569616B7875647379716568737A7168796B67677379796C6B767669

base16解码:

lvueiakxudsyqehszqhykggsyylkvvi

1
//The last layer is the single table replacement password

注释提示是单表替换密码,就那么几种,最简单的凯撒,肯定不是,跟flag格式对不上。

应该是仿射密码(密码学课上刚学,天选之子),python脚本:

1
2
3
4
5
6
7
8
9
10
11
12
a=[1,3,5,7,9,11,15,17,19,21,23,25]
c='lvueiakxudsyqehszqhykggsyylkvvi'
str=''
for k2 in range(26):
for k1 in a:
for ci in range(len(c)):
k=chr((((ord(c[ci])-97-k2)*k1)%26)+97)
str+=k
if len(str)==len(c):
print(str,k1,k2)
str=''

跑一下,结果如图:

clip_image026

Misc2

0x01

下载得到1.xlsx,直接打开,提示损坏,不行。

老套路,直接尝试binwalk -e 分离文件,如图:

clip_image028

clip_image029

得到RC4data.txt,直接爆?不可能!应该有秘钥,还得接着找。

继续binwalk -e swpu.xls,如图,得到RC4key的压缩包,解压提示有密码,尝试爆破,不行。

clip_image031

clip_image032

继续binwalk -e esayrc4.xlsx,如图:

clip_image034

clip_image036

最后将0.zip以txt文本形式打开在最后面找到压缩包密码:

clip_image038

解压缩包得到RC4的秘钥:

1
ABCDEFGHIJKLMNOPQRSTUVWXYZ

在线解密(https://www.sojson.com/encrypt_rc4.html):

clip_image040

加上flag{}就是结果了。

RSA:

打开链接得到密文,模数e和两个带有pq的表达式,判断出是RSA解密:

clip_image042

p,q是互素的,表达式1等价为:q(1+p)(p^2-p+1),表达式2等价于:pq(1+p)

最大公因式为q(1+p)。然后可通过表达式2求出p,再求q,然后便很容易求解。写脚本及运行结果如下:

clip_image044

Crypto2

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
from Crypto.Cipher import AES
import os
flag='flag{********************************}'
BLOCKSIZE = 16

def pad(data):
pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if len(data) % BLOCKSIZE != 0 else 0
return data + "=" * pad_len

def unpad(data):
return data.replace("=","")

def enc(data,key,iv):
cipher = AES.new(key,AES.MODE_CBC,iv)
encrypt = cipher.encrypt(pad(data))
return encrypt

def dec(data,key,iv):
try:
cipher = AES.new(key,AES.MODE_CBC,iv)
encrypt = cipher.decrypt(data)
return unpad(encrypt)
except:
exit()

def task():
try:
key = os.urandom(16)
iv = os.urandom(16)
pre = "yusa"*4
for _ in range(3):
choice = raw_input(menu)
if choice == '1':
name = raw_input("What's your name?")
if name == 'admin':
exit()
token = enc(pre+name,key,iv)
print "Here is your token(in hex): "+iv.encode('hex')+token.encode('hex')
continue
elif choice == '2':
token = raw_input("Your token(in hex): ").decode('hex')
iv = token[:16]
name = dec(token[16:],key,iv)
print iv.encode('hex')+name.encode('hex')
if name[:16] == "yusa"*4:
print "Hello, "+name[16:]
if name[16:] == 'admin':
print flag
exit()
else:
continue
except:
exit()
menu='''
1. register
2. login
3. exit
'''
if __name__ == "__main__":
task()

字节翻转攻击,参考

https://my.oschina.net/u/4330970/blog/3492384

https://www.t00ls.net/articles-29459.html

两密文块,通过对密文1进行修改,使得密文块2解密得到admin.

但是因此可能使得第一个密文块解密出乱码。并且题中需要密文1的值是yusayusayusayusa.

由于是三次交互,第一次用于登陆,第二次用于改密文块1,从而使密文块2解密得到admin。

第三次交互,需要从第二次交互的输出中提取密文块1的plaintext,与yusayusayusayusa进行异或之后,与iv进行异或,作为新的iv。这样即使aes cbc解密出乱码也可以,乱码会被iv抵消掉。

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
import struct 
from binascii import *

def str_xor(t1, t2):
l = min(len(t1), len(t2))
response = b''
for i in range(l):
temp = t1[i] ^ t2[i]
response += struct.pack('B', temp)
return response

token = unhexlify('ac4d9724e337e7392fe2e335dfcbb1ab66d13bbd22eb85f56e9e4625423e0caa18be17a9828fbd98e44a01a4278ce552')
iv, enc1, enc2 = token[:16], token[16:32], token[32:]
n_enc1 = str_xor(enc1, str_xor(b'aron3', b'admin')) + enc1[5:]
print(enc1)
print(n_enc1)
result = iv + n_enc1 + enc2
print(result)
print('first:', hexlify(result))
print('\n\n\n\n')

token2 = unhexlify('ac4d9724e337e7392fe2e335dfcbb1abf885abf953702268604ab22ef8794f0961646d696e')
enc1_2 = token2[16:32]
print(enc1_2)
n_iv = str_xor(iv, str_xor(enc1_2, b'yusayusayusayusa'))
print(n_iv)
result2 = n_iv + n_enc1 + enc2
print('second:', hexlify(result2))

结果如图:

clip_image046

clip_image048

Crypto3

源码如下:

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
from Crypto.Cipher import AES
import os
BLOCKSIZE = 16
flag='flag{********************************}'


def pad(data):
pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if len(data) % BLOCKSIZE != 0 else 0
return data + chr(pad_len) * pad_len

def unpad(data):
num = ord(data[-1])
return data[:-num]


def enc(data,key):
cipher = AES.new(key,AES.MODE_ECB)
encrypt = cipher.encrypt(pad(data))
return encrypt


def dec(data,key):
try:
cipher = AES.new(key,AES.MODE_ECB)
encrypt = cipher.decrypt(data)
return unpad(encrypt)
except:
exit()


def task():
try:
key = os.urandom(16)
while True:
plaintext = raw_input("Amazing function: ").decode('hex')
yusa = plaintext+flag
print enc(yusa,key).encode('hex')
except Exception as e:
print str(e)
exit()
if __name__ == "__main__":
task()

根据提示和百度引擎,现学ECB Byte at Time(参考文章:https://www.jianshu.com/p/8aef410a2eae

因为我们不能提前知道flag长度,只能通过更改明文plaintext的长度进行测试,

最终可以判断flag长度是38。

参考:ECB Byte at Time - scriptkid - 博客园 (cnblogs.com)

每次爆破一个字符

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
from pwn import *
from binascii import *

context.log_level = 'debug'
p = remote('das.wetolink.com', 42887)

def ecb(n):
h = hex(n)[2:]
return struct.pack('B', ord(h[0])) + struct.pack('B', ord(h[1]))

enc = []

for i in range(38):
payload = b'88' * (47-i)
p.sendlineafter(b'Amazing function: ', payload)
enc.append(p.recvline()[64:96])

#print(enc)
flag = b''

for i in range(38):
f = False
for c in range(32, 127):
payload = b'88' * (47-len(flag)//2) + flag + ecb(c)
p.sendlineafter(b'Amazing function: ', payload)
e = p.recvline()[:-1]
if e[64:96] in enc:
flag += ecb(c)
#print(flag)
f = True
break
if not f:
exit()

print(unhexlify(flag))

python跑的结果如下:

clip_image050

CATALOG
  1. 1. Web1
    1. 1.1. 0x01 扫描目录加注入
    2. 1.2. 0x02登录
    3. 1.3. 0x03文件上传
  2. 2. Misc1
    1. 2.1. 0X01
  3. 3. Misc2
    1. 3.1. 0x01
  4. 4. Crypto2
  5. 5. Crypto3