近来档期满满,隔天就一场。猝si的感jio。 越来越菜,也就只能帮二进制爷爷打打杂交交flag这样啦。 just do it.
强网先锋 upload 简单题。给了流量包,结合题目名,八九不离十。直接滤http流,找到了图片上传。
保存下来,结合图片名称hint知道是steghide隐写。直接上工具,题目应该要爆破密码,但是盲猜123456猜中了。
Funhash 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 <?php include 'conn.php' ;highlight_file("index.php" ); if ($_GET ["hash1" ] != hash("md4" , $_GET ["hash1" ])){ die ('level 1 failed' ); } if ($_GET ['hash2' ] === $_GET ['hash3' ] || md5($_GET ['hash2' ]) !== md5($_GET ['hash3' ])){ die ('level 2 failed' ); } $query = "SELECT * FROM flag WHERE password = '" . md5($_GET ["hash4" ],true ) . "'" ;$result = $mysqli ->query($query );$row = $result ->fetch_assoc(); var_dump($row ); $result ->free();$mysqli ->close();?>
hash考点 level1弱比较,找一个0e开头的明文0e251288019
md4后也是0e开头的hash即可绕过 level2 md5强比较,用数组绕过 level3 md5 sql注入,开启了raw输出,找到一个hash为x' or xx...
的明文ffifdyop
即可 payload:
1 ?hash1=0e251288019&hash2[]=111&hash3[]=222&hash4=ffifdyop
bank 上来先sha256爆破,题目提示了明文的字符空间是大小写加数字,简单爆破即可。然后给队伍的token。 一个银行系统。先看hint,给了一段代码。
1 2 3 4 5 6 7 def transact_ecb (key, sender, receiver, amount ): aes = AES.new(key, AES.MODE_ECB) ct = b"" ct += aes.encrypt(sender) ct += aes.encrypt(receiver) ct += aes.encrypt(amount) return ct
可以知道是基于AES加密的转账系统。 初始时有10cash,拿flag需要1000cash。 常规的转账是,先通过transact拿到由服务器加密的record,然后provide上去即可完成转账。 可以通过view看到全部转账记录(包括别人的) 那么可以考虑通过篡改别人的记录,将接收者改为自己,伪造别人给自己转账。 在record生成代码中,采用发送者+接收者+金额的密文拼接方式。一条record长96个字符,48个字节。那么前16个字节就是发送者的密文,中间16个字节是接收者,后16个字节是金额。 思路清晰:先生成一条自己给别人转账的record,取前16字节就是自己NickName的密文。然后将所有record的中间16个字节替换成自己的密文再全部提交上去。即可伪造别人给自己转账。 exp:
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 import stringimport hashlibfrom zio import *from itertools import permutationsdef hash_sha256 (text ): s = hashlib.sha256() s.update(text.encode("utf8" )) return s.hexdigest() def auth (io ): io.read_until("sha256(XXX+" ) salt = io.read_until(")" )[:-1 ] io.read_until("== " ) hash1 = io.read_until("G" )[:-2 ] space = string.ascii_letters + string.digits for text_tuple in permutations(space, 3 ): text = '' .join(text_tuple) + salt enc = hash_sha256(text) if enc == hash1: io.read_until("XXX:" ) io.writeline(text[:3 ]) return ip = "39.101.134.52" port = 8005 teamtoken = "icqa4f7d3d27c218f218c1ce95559eea" target=(ip,port) io = zio(target, timeout=10000 , print_read=COLORED(RAW,'red' ), print_write=COLORED(RAW,'green' )) auth(io) io.read_until("teamtoken:" ) io.writeline(teamtoken) io.read_until("name:" ) io.writeline("sncker" ) io.read_until("> " ) io.writeline("transact" ) io.read_until("> " ) io.writeline("a 1" ) myname_hash = io.read(32 ) io.read_until("> " ) io.writeline("view records" ) io.read_until("more than 100" ) r_hash = io.read(10 * 96 + 10 )[1 :] r_list = r_hash.split('\x0a' ) for _ in range (10 ): io.read_until("> " ) io.writeline("provide a record" ) io.read_until("> " ) io.writeline(r_list[_][:32 ] + myname_hash + r_list[_][64 :]) io.interact()
红方辅助 给了一个流量包和一个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 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 import socketimport structimport multiprocessingimport randomfrom hashlib import md5, sha256IP = "xxx.xxx.xxx.xxx" PORT = 10235 def GetSalt (data ): return int ((md5(sha256(data.encode()).digest())).hexdigest(), 16 ) % 256 def encrypt (data, btime, count ): funcs = { "0" : lambda x, y : x - y, "1" : lambda x, y : x + y, "2" : lambda x, y : x ^ y } offset = { "0" : 0xefffff , "1" : 0xefffff , "2" : 0xffffff , } length = len (data) + 10 fn = str (random.randint(0 , 65535 ) % 3 ).encode() salt = GetSalt(data) t = struct.unpack("<i" , btime)[0 ] boffset = offset[fn.decode()] t -= boffset t = struct.pack("<i" , t) enc = struct.pack("<IIcB" , count, length, fn, salt) i = 0 for c in data: enc += chr ((funcs[fn.decode()](ord (c) ^ ord (t[i]), salt) % 256 )) i = (i + 1 ) % 4 return boffset, enc def SendMessage (ClientSocket ): f = open ("data.txt" , "r" ) readlines = f.readlines() f.close() count = 0 for readline in readlines: try : ClientSocket.send("G" ) btime = ClientSocket.recv(4 ) boffset, data = encrypt(readline, btime, count) ClientSocket.send(struct.pack("<i" , boffset)) ClientSocket.send(data) pcount = struct.unpack("<i" , ClientSocket.recv(4 ))[0 ] count += 1 if pcount != count: print("error!" ) break except : print("error!" ) break ClientSocket.close() if __name__ == '__main__' : ClientSocket = socket.socket(family = socket.AF_INET, type = socket.SOCK_STREAM) ClientSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) ClientSocket.connect((IP,PORT)) SendMessage(ClientSocket) ClientSocket.close()
粗略看了脚本可以知道是数据处理+网络传输协议。那么就要从抓包流量中逆向出原数据。 因为知道了端口所以可以直接过滤出指定端口的流量。然后保存下来。 看到加密函数里的主要处理代码。
1 enc += chr ((funcs[fn.decode()](ord (c) ^ ord (t[i]), salt) % 256 ))
对照写出解密过程。
1 m += chr ((funcs[fn.decode()](ord (c), salt) ^ ord (t[i])) % 256 )
对应的funcs
也要改为逆函数。
1 2 3 4 5 funcs = { "0" : lambda x, y : x + y, "1" : lambda x, y : x - y, "2" : lambda x, y : x ^ y }
看脚本可以知道数据分段传输,长度都一样,除了最后一段。但长度信息包含在数据头部所以不影响。 通过分析可以对数据进行划分。 解密过程需要的参数为fn, salt, t
fn,salt
都能直接取到。t
朔源可知由btime
和boffset
决定,这两个也可以取到。 复制加密函数,简单修改一下即可得出解密函数。 exp:
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 import socketimport structimport multiprocessingimport randomfrom hashlib import md5, sha256def GetSalt (data ): pass def encrypt (data, btime, count ): pass def decrypt (data, btime, boffset, count, fn, length, salt ): funcs = { "0" : lambda x, y : x + y, "1" : lambda x, y : x - y, "2" : lambda x, y : x ^ y } offset = { "0" : 0xefffff , "1" : 0xefffff , "2" : 0xffffff , } t = struct.unpack("<i" , btime)[0 ] boffset = offset[fn.decode()] t -= boffset t = struct.pack("<i" , t) i = 0 m = "" for c in data: m += chr ((funcs[fn.decode()](ord (c), salt) ^ ord (t[i]))%256 ) i = (i + 1 ) % 4 return boffset, m def SendMessage (ClientSocket ): pass if __name__ == '__main__' : with open ("alldata" , "rb" ) as f: with open ("flag.txt" , "w+" ) as f1: while True : f.read(1 ) btime = f.read(4 ) boffset = struct.unpack("<i" , f.read(4 ))[0 ] count = struct.unpack("<l" , f.read(4 ))[0 ] length = struct.unpack("<l" , f.read(4 ))[0 ] fn = struct.unpack("<c" , f.read(1 ))[0 ] salt = struct.unpack("<B" , f.read(1 ))[0 ] data = f.read(length - 10 ) f.read(4 ) a, m = decrypt(data, btime, boffset, count, fn, length, salt) f1.write(m)
打开flag.txt 还要手动拼一下,有点小过分:)
1 QWB{3e752bf509ddb4e9a42f1ef30beff495}