jarvis OJ writeup (Misc部分)

简单网管协议

发现snmp协议,跟踪UDP流可发现
简单网管协议
flag{077149a68b9d4f25f52bb11530f44028}

下载看到是张bmp图片,头部有缺失,补上424D,保存发现只是张普通的图片,发现最后有IEND的png结尾,使用dd将其裁剪出来

1
dd if=./phrack.bmp of=out.png ibs=0x1171a9 skip=1 count=1

发现ihdr有错误,根据ihdr crc32爆破出相应的w,h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import binascii
import struct

with open("./out.png",'rb') as f:
data = f.read()
f.close()
crc = struct.unpack(">I",data[29:33])[0]
for w in range(1024):
for h in range(1024):
ihdr = b"IHDR"+ struct.pack(">I",w) + struct.pack(">I",h)+b"\x08\x02\x00\x00\x00"
if crc == binascii.crc32(ihdr):
data = data[:12]+ihdr+data[29:]
break
with open("out2.png","wb") as f:
f.write(data)
f.close()

#PCTF{CrC32_i5_Useful_iN_pNG}

Scan

Wireshark打开,发现开头是个icmp,推测每次扫描之前都要用icmp测试一下,然后过滤icmp
Scan
从后往前一个个试,最后发现为155989这个

1
2
3
echo -n 155989|openssl dgst -sha256

#PCTF{0be2407512cc2a40bfb570464757fd56cd0a1d33f0bf3824dfed4f0119133c12}

远程登录协议

过滤telnet追踪TCP流,发现
远程登陆协议
FLAG:f69dd04e38ef85e38b2f148475ce32bc

shell流量分析

追踪TCP流发现一个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
#!/usr/bin/env python
# coding:utf-8
__author__ = 'Aklis'

from Crypto import Random
from Crypto.Cipher import AES

import sys
import base64

def decrypt(encrypted, passphrase):
IV = encrypted[:16]
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.decrypt(encrypted[16:])

def encrypt(message, passphrase):
IV = message[:16]
length = 16
count = len(message)
padding = length - (count % length)
message = message + '\0' * padding
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.encrypt(message)

IV = 'YUFHJKVWEASDGQDH'

message = IV + 'flag is hctf{xxxxxxxxxxxxxxx}'

print len(message)

example = encrypt(message, 'Qq4wdrhhyEWe4qBF')
print example
example = decrypt(example, 'Qq4wdrhhyEWe4qBF')
print example

后边发现密文:

shell流量分析
将脚本改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
import base64
from Crypto import Random
from Crypto.Cipher import AES

def decrypt(encrypted, passphrase):
IV = encrypted[:16]
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.decrypt(encrypted[16:])

IV = 'YUFHJKVWEASDGQDH'

message = "mbZoEMrhAO0WWeugNjqNw3U6Tt2C+rwpgpbdWRZgfQI3MAh0sZ9qjnziUKkV90XhAOkIs/OXoYVw5uQDjVvgNA==".decode("base64")

example = decrypt(message, 'Qq4wdrhhyEWe4qBF')
print example

#flag is hctf{n0w_U_w111_n0t_f1nd_me}

webshell分析

分析流量发现一个访问了一个ironshell.php的文件,猜测这就是webshell 。用如下规则过滤出来

1
ip.addr == 115.28.102.80 && http.request.uri matches "ironshell.php"

webshell分析
发现最后一个包的url里有个flag猜测这个包里就有要的关键数据,跟踪TCP流将其数据dump出来保存到一个html里
webshell分析
发现疑似flag的东西,解base64发现是个url访问是张二维码,扫码可得flag

1
2
3
➜  findwebshell echo "aHR0cHM6Ly9kbi5qYXJ2aXNvai5jb20vY2hhbGxlbmdlZmlsZXMvQWJUekEyWXRlRmpHaFBXQ2Z0cmFvdVZEM0I2ODRhOUEuanBn"|base64 -D
https://dn.jarvisoj.com/challengefiles/AbTzA2YteFjGhPWCftraouVD3B684a9A.jpg
#flag{1542ae716e47576e1f3e36326a23e72e}

flag

binwalk分析下发现有个压缩包

flag
猜测LSB隐写,stegsolve打开发现一个zip

flag
Dump发现打不开,再来binwalk一下,解出来一个elf文件。。。
flag
ida打开
flag

1
#hctf{dd0gf4c3tok3yb0ard4g41n~~~}

misc100

下来看看是个apk,直接用dex2jar转诊jar然后jd-gui打开

1
➜  easy100 d2j-dex2jar.sh easy100.apk

misc100
直接就看到这个,猜测这应该就是加密之后的,继续看

misc100
这里调用了MainActivity.a,两个参数,一个是MainActiviry.a(this.a)的返回值,一个是输入的字符串
然后看看c.a()都干了啥,c这个类里有2个叫a的方法,应该是重写的,先看2个参数的那个

misc100
New了一个a类,

misc100
所以当初调用的时候第一个参数是key,第二个参数就是明文然而我并不知道第一iv是啥,一度以为是空字符串的md5…本垃圾不懂java,不太懂,,研究了一下,貌似这个MaivAvtive.p()没人调用,就猜第一个参数应该是这个v。
然后将v的每两位换一下。写个脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Cipher import AES
from struct import pack as p

with open("./easy100/assets/url.png","rb") as f:
change_key = f.read()[144:144+16]
f.close()

key = bytearray()
for _ in range(0,16,2):
key.append(change_key[_+1])
key.append(change_key[_])

a = [21, -93, -68, -94, 86, 117, -19, -68, -92, 33, 50, 118, 16, 13, 1, -15, -13, 3, 4, 103, -18, 81, 30, 68, 54, -93, 44, -23, 93, 98, 5, 59]
b = b""
for _ in a:
b+=p("b",_ )

c = AES.new(bytes(key),AES.MODE_ECB)
m = c.decrypt(b)
print(m)
#LCTF{1t's_rea1ly_an_ea3y_ap4}

you_need_python

解压一看是个脚本和一个乱码文件,文件名根据提示rfc4042知道那个文件是utf9编码的解码后是个字符串加加减减的,然后flag.py里的是python的字节码,写个脚本将其转成pyc

1
2
3
4
5
6
7
8
9
10
def to_pyc(code,filename):
data = bytearray(imp.get_magic())
data += struct.pack("<L",int(time.time()))
data += code
with open(filename,"wb") as f:
f.write(data)
f.close()

code = zlib.decompress(base64.b64decode('eJxtVP9r21YQvyd/ieWm66Cd03QM1B8C3pggUuzYCSWstHSFQijyoJBhhGq9OXJl2ZFeqAMOK6Q/94f9Ofvn1s+d7Lgtk/3O997du/vc584a0eqpYP2GVfwDEeOrKCU6g2LRRyiK4oooFsVVUSqkqxTX6J1F+SfSNYrrdKPorC76luhbpOEGCZNFZw2KG3Rmk26QtuXi3xTb7ND6/aVu0g2RuvhEcZNut5lAGbTvAFbyH57TkYLKy8J6xpDvQxiiiaIlcdqJxVcHbXY6bXNlZgviPCrO0+StqfKd88gzNh/qRZyMdWHE29TZZvIkG7eZFRGGRcBmsXJaUoKCQ9fWKHwSqNeKFnsM5PnwJ7q2aKk4AFhcWtQCh+ChB5+Lu/RmyYUxmtOEYxas7i/2iuR7Ti14OEOSmU0RADd4+dQzbM1FJhukAUeQ+kZROuLyioagrau76kc1slY1NNaY/y3LAxDQBrAICJisV2hMdF2lxQcyFuMoqcX3+TCl6xotqzSpkqmxYVmjXVjAXiwBsEfBrd1VvTvLCj2EXRnhoryAKdpxcIgJcowUB68yAx/tlCAuPHqDuZo0CN3CUGHwkPhGMA7aXMfphjbmQLhLhJcHa0a+mpgB191c1U1lnHJQbgkHx+WGxeJbejnpkzSavo2jkxZ7i725npGAaTc8FXmUjbUETHUmkxXN5zqL5WiWxwE7Bc11yyYzNJpN02jerq+DzNNodfxOX8kE4FcmYKscDdYD1oPGGucXYNmgs1F+NTf3GOt3Mg7b+NTVruqoQyX1hOEUacKw+AGbP38ZOq9THRXaSbL5pXGQ8bho/Z/lrzQaHxdoCrlev+t6nZ7re57r+57rHXag93Deh37k+vuw9zorO/Qj/B50cAf2oyOsvut3D+ADWxdxfN/1Drqu39mHzvcRswv/Hvz7sHeg9w8Qzy99DzuFwxhPhs6zWTbOI3OZRiaZZcVj5wVwOklx7OwVxR47PR46r/SVM8ulBJic9zku/eqY/MqJxiDj+Gd55wS3f35pbLCzHoEwzKKpDkN5i+TR+1AYCWTo5IV0Z0P9H3phDDd6lMzPdS5bbo9eJGbTsW9nbDqLL1N9Iq+rRxDbll2x67a9Lf27hw5uK1s1rZr6DOPF+FI='))
to_pyc(code,"dump.pyc")

然后使用 uncompyle6 将pyc反编译乘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
35
36
37
38
39
40
41
42
43
44
➜  you_need_python uncompyle6 ./dump.pyc >source.py
➜ you_need_python cat ./source.py
# uncompyle6 version 3.3.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.7.1 (default, Nov 6 2018, 18:46:03)
# [Clang 10.0.0 (clang-1000.11.45.5)]
# Compiled at: 2019-04-23 15:00:53
import hashlib

def sha1(string):
return hashlib.sha1(string).hexdigest()


def calc(strSHA1):
r = 0
for i in strSHA1:
r += int('0x%s' % i, 16)

return r


def encrypt(plain, key):
keySHA1 = sha1(key)
intSHA1 = calc(keySHA1)
r = []
for i in range(len(plain)):
r.append(ord(plain[i]) + int('0x%s' % keySHA1[i % 40], 16) - intSHA1)
intSHA1 = calc(sha1(plain[:i + 1])[:20] + sha1(str(intSHA1))[:20])

return ('').join(map(lambda x: str(x), r))


if __name__ == '__main__':
key = raw_input('[*] Please input key:')
plain = raw_input('[*] Please input flag:')
encryptText = encrypt(plain, key)
cipherText = '-185-147-211-221-164-217-188-169-205-174-211-225-191-234-148-199-198-253-175-157-222-135-240-229-201-154-178-187-244-183-212-222-164'
if encryptText == cipherText:
print '[>] Congratulations! Flag is: %s' % plain
exit()
else:
print '[!] Key or flag is wrong, try again:)'
exit()
# okay decompiling ./dump.pyc

我们可以看到key为utf9解出的那串字符串,然后sha1算hash再每一个字符按16进制加起来,那么我们现在知道keySHA和intSHA1,那么flag的第一位就是

1
x + int(keySHA1[0],16) - intSHA1 = -185

解方程就能求得flag了,所以现在的关键就是解出key

1
2
3
4
5
6
7
8
import utf9
def getkey():
with open('./key_is_here_but_do_you_know_rfc4042','rb') as f:
data = utf9.utf9decode(f.read())
f.close()
print(data)

#key: _____*((__//__+___+______-____%____)**((___%(___-_))+________+(___%___+_____+_______%__+______-(______//(_____%___)))))+__*(((________/__)+___%__+_______-(________//____))**(_*(_____+_____)+_______+_________%___))+________*(((_________//__+________%__)+(_______-_))**((___+_______)+_________-(______//__)))+_______*((___+_________-(______//___-_______%__%_))**(_____+_____+_____))+__*(__+_________-(___//___-_________%_____%__))**(_________-____+_______)+(___+_______)**(________%___%__+_____+______)+(_____-__)*((____//____-_____%____%_)+_________)**(_____-(_______//_______+_________%___)+______)+(_____+(_________%_______)*__+_)**_________+_______*(((_________%_______)*__+_______-(________//________))**_______)+(________/__)*(((____-_+_______)*(______+____))**___)+___*((__+_________-_)**_____)+___*(((___+_______-______/___+__-_________%_____%__)*(___-_+________/__+_________%_____))**__)+(_//_)*(((________%___%__+_____+_____)%______)+_______-_)**___+_____*((______/(_____%___))+_______)*((_________%_______)*__+_____+_)+___//___+_________+_________/___

一开始以为是xxfuck之类的、、最后查了一下发现就是单纯的下划线的算式,

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
import utf9
import hashlib

def sha1(string):
return hashlib.sha1(string).hexdigest()


def calc(strSHA1):
r = 0
for i in strSHA1:
r += int('0x%s' % i, 16)
return r


def getkey():
with open('./key_is_here_but_do_you_know_rfc4042','rb') as f:
data = utf9.utf9decode(f.read())
f.close()
_ = 1
__ = 2
___ = 3
____ = 4
_____ = 5
______ = 6
_______ = 7
________ = 8
_________ = 9
__________ = 0
key = eval(data)
return hex(key)[2:].decode('hex')


def decrypt(key):
c = '-185-147-211-221-164-217-188-169-205-174-211-225-191-234-148-199-198-253-175-157-222-135-240-229-201-154-178-187-244-183-212-222-164'
c = [int(c[x:x+4]) for x in xrange(0,len(c),4)]
keySHA1 = sha1(key)
intSHA1 = calc(keySHA1)
m = ''
for _ in xrange(len(c)):
m += chr(c[_] + intSHA1 - int('0x%s' % keySHA1[_ % 40], 16))
intSHA1 = calc(sha1(m[:_+1])[:20] + sha1(str(intSHA1))[:20])
return m
key = getkey()
print key
m = decrypt(key)
print m
#key: I_4m-k3y
#flag{Lif3_i5_5h0r7_U_n33d_Py7h0n}

Struts2漏洞

一说structs2就想到反序列化,但是本垃圾并不懂java,更别说structs2了,查了一下原理,看到这个
https://blog.csdn.net/wpydaguan/article/details/45220025

Struts2漏洞
于是猜测,url里有action关键字,用wireshark的正则匹配一下

1
http and !(http.request.uri matches "http://.*\.jpg.*" or http.request.uri matches "http://.*\.gif.*" ) and http.request.uri matches ".*action.*"

Struts漏洞
不多一个个看:

Struts漏洞
FLAG:E3274BE5C857FB42AB72D786E281B4B8

WPA2

首先nc连上去看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
➜  ~ nc pwn.jarvisoj.com 9893
Welcome to HuWang Bei WPA2 Simulation System.. Initilizing Parameters..

SSID = HuWang

PSK = eygqW2NkTrmXfV94

AP_MAC = E2:73:76:65:9A:F0

AP_Nonce = fa2e6fbd9c1248451fba5f112773528f52907c795d89ba32102e00f60074922e

STA_MAC = E9:88:69:8F:26:06

STA_Nonce = 85dd88520e836988028459c710284424a15af2b2884be36623d9d9b8c90cf2ab

CCMP Encrypted Packet = 88423a01e988698f2606e27376659af0e27376659af060920000319c00200f00000023102cb86f5f401b2333e536a9148311f13b4d31e3c6556b3f0c7f6a3c4d058ce7d0ea87e2131d46a3

Input decrypted challenge value in Packet:

google一下,研究了半天懂了一点,WPA2是通过SSID与PSK生成一个PMK,然后通过PMK, AP nonce, STA nonce (SNonce), AP MAC address , and STA MAC address生成PTK,PTK又分为若干部分:
EAPOL-Key Confirm Key、EAPOL-Key Encrypt Key用于EAPOL-Key的四次握手,
(TKIP|CCMP) Temporal Key 参与报文加密解密
TKIP MIC Key(for Authenticator Tx)、TKIP MIC Key(for Supplicant Tx)用于TKIP协议。
看到题目给的信息、我估计就是要算那个(TKIP|CCMP) Temporal Key了。
首先是通过SSID与PSK计算PMK,这里可以用WPA key calculation: From passphrase to hex也可以自己写个脚本具体的算法可以看 rfc2898 的PBKDF2那一节…
然后我写了一半发现python3有自带的。。。。

1
PMK = hashlib.pbkdf2_hmac("sha1", PSK.encode(), SSID.encode(), 4096, 256)

PTK的算法见IEEE 802.11-04/0123r1 46页

1
2
802.11i-PRF(K, A, B, Len) R ← “” for i ← 0 to ((Len+159)/160) – 1) do R ← R || HMAC-SHA1(K, A || B || i) return Truncate-to-len(R, Len)
PTK ← 802.11i-PRF(PMK, “Pairwise key expansion”, min(AP-Addr, STA-Addr) || max(AP-Addr, STA-Addr) || min(ANonce, SNonce) || max( ANonce, SNonce), 384)

写了脚本计算出了Temporal Key然后还没完的呢。
根据RFC 3610 的说法,要解密CCM加密的密文,要提供三个东西,
密钥,随机数,附加认证数据,密钥我们已经有了。然后随机数和附加认证数据去哪搞是个问题emmmm。根据IEEE 802.11-04/0123r1 33页说的

  • Needs one fresh 128-bit key – Same 128-bit
    • Temporal key used by both AP and STA
    • CBC-MAC IV, CTR constructions make this valid
  • Nonce (A0, B0) construction in CCMP’s use of CCM:
    • A0 = Tag0 || 0x00 || Transmit-Address || Frame-Sequence-Number
    • B0 = Tag1 || 0x00 || Transmit-Address || Frame-Sequence-Number
    • Transmit-address is 6 octets
    • Frame-Sequence-Number is 8 octets and includes the QoS Priority
    • Sequence-Number must be sequential within a single MSDU
      emmmmmmmmm

未完待续…