内容简介:今年的签到题就直接pass了,从第二道开始。题目就给出了一串一开始是想看看是不是什么文件的,但没有发现。
前言
今年的 DDCTF
玩的非常充实,7天的时间里基本每天都在学习新东西,整个 Writeup
会按题目类型进行分类。
(╯°□°)╯︵ ┻━┻
签到题就直接pass了,从第二道开始。题目就给出了一串 16进制
的字符:
d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd
一开始是想看看是不是什么文件的,但没有发现。
而且观察发现按两位数转10进制的话全都超出了可见字符的 ASCII
码表,当然解题时也考虑过对每两个16进制进行 ^
异或,但都不对。然后尝试对每两个字符转出来的 10进制
进行减 128
,因为这样每个值得范围就能落在 ASCII
码表。
import re sss = 'd4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd' nums = re.findall('\w{2}',sss) flag = '' for one in nums: ch = chr(int(one,16) - 128) flag += ch print(flag) # That was fast! The flag is: DDCTF{922ab9974a47cd322cf43b50610faea5}
第四扩展FS
附件下下来发现很大,用 winhex
查看了一下,发现后面全是填充的,然后还有个压缩包,我们把它提取出来,但需要解压密码,然后解压密码可以在原图片的 备注
信息里找到。
接着我们就能拿到一堆乱码的字符。
因为题目描述中说到 频次
很重要,所以尝试使用在线的词频密码分析网站,但没有发现,所以考虑另一种可能,就是不用还原成句子,只需要里面的每个词的频次。然后写个脚本跑一下:
# -*- coding:utf-8 -*- with open ('file.txt','r') as f: dd3 = f.read() a = {} for i in dd3: if i not in a: a[i]=1 else: a[i] +=1 b = sorted(a.items(), lambda x, y: cmp(x[1], y[1]), reverse=True) flag = '' for i in b: flag += i[0] print(flag) # DCTF{x1n9shaNgbIci}
流量分析
下载后使用 wireshark
进行分析,流量分析题如果不掌握点小技巧,估计眼睛会看瞎。
打开后直接拉到 灰色
报文块,如下图,然后一把 TCP追踪流
过去。
然后逐个查看流,然后你会发现有两个压缩包,但后面发现那就是坑来的,反正我没用上。。。。在查看他们的邮件往来记录的时候有一张图片引起了我的注意:
恢复过来后看起来比较奇怪,,因为以前也没搞过密码,所以一开始还真没注意到它的作用。
接着再往下走,有一个地方引起了我的注意。
TLSv1.2
是 https
上使用的,后面的传输数据都会被服务器的私钥进行加密,然后这时想起上面得到的那张图片,就联系起来了。百度了一下在 wireshark
里还原 https
数据的方法: 传送门 。按照这里的方法进行恢复,然后就能拿到flag了。
PS一下:这里对我提取出来的文件进行 md5
,但都没有得到题目中给的那个值。。。
安全通信
题目描述:
请通过nc 116.85.48.103 5002答题,mission key是f49348cf84d390da52498077ae7137d5,agent id随意填就可以
#!/usr/bin/env python import sys import json from Crypto.Cipher import AES from Crypto import Random def get_padding(rawstr): remainder = len(rawstr) % 16 if remainder != 0: return '\x00' * (16 - remainder) return '' def aes_encrypt(key, plaintext): plaintext += get_padding(plaintext) aes = AES.new(key, AES.MODE_ECB) cipher_text = aes.encrypt(plaintext).encode('hex') return cipher_text def generate_hello(key, name, flag): message = "Connection for mission: {}, your mission's flag is: {}".format(name, flag) return aes_encrypt(key, message) def get_input(): return raw_input() def print_output(message): print(message) sys.stdout.flush() def handle(): print_output("Please enter mission key:") mission_key = get_input().rstrip() print_output("Please enter your Agent ID to secure communications:") agentid = get_input().rstrip() rnd = Random.new() session_key = rnd.read(16) flag = '<secret>' print_output(generate_hello(session_key, agentid, flag)) while True: print_output("Please send some messages to be encrypted, 'quit' to exit:") msg = get_input().rstrip() if msg == 'quit': print_output("Bye!") break enc = aes_encrypt(session_key, msg) print_output(enc) if __name__ == "__main__": handle()
这道题考的是 aes ecb
的攻击方法,经过一通 google
后找到了一个比较有参考意义的writeup,传送门。
需要了解的是 ECB
是 分组
加密的(一组16个字符),也就是一块一块的,这点是我们后续攻击的重要前提。
然后我们看一下他这个脚本,经过分析后我们可以发现加密的消息的 长度
我们是可以控制的。
而且对于一次 连接
,在同一密钥的情况下,我们可以随意加密任何数据任何次。
所以攻击手段就很清晰了。
明文分组(16个字符) 对于的密文(对得到的一长串密文进行32位切割) Connection for m ----> eae138090c7a60d97a6c54ce15fe7888 # 第1块 ission: 12345678 ----> aaaab01d2ba84861447153e790047db4 # 第2块 90123, your miss ----> d9d2a15efa5c6f75097d89f1e5cc629c # 第3块 ion's flag is: D ----> 8e16cf020a37e52a28fdee32d469c2b4 # 第4块 DCTF{afafjafj101 ----> 5ca9b0e48d1dec7bb06a73dd163380a0 # 第5块 .....
如上所示,我们可以控制 name
的长度来使(在这种情况下) 第4块
的最后一个字符是 flag
中我们要求的第一个字符,而它明文的前15个字符我们是知道的,密文我们也知道,所以我们可以使用这样来暴力猜测出 最后一位
到底是什么。
# 伪代码 raw = 'ion's flag is: ' for ch in range(33,128): tmp = raw + chr(ch) my_miwen = encrypt(tmp) if my_miwen == true_miwen: print('要求的是:',tmp)
所以只要我们设计好 填充的长度
就能将flag的所有字符都爆破出来。填充的时候有一个需要注意的地方就是块的 推进
(进位),因为你不能无限制退后,所以当我们用完填充块的大小后要更新需要爆破的块。代码如下:
# coding:utf-8 import socket # 导入 socket 模块 import re sc = None c = '-' def sendAgent(agent): global sc sc = socket.socket() # 创建 socket 对象 host = "116.85.48.103" # 获取本地主机名 port = 5002 # 设置端口 addr = (host, port) sc.connect(addr) # 绑定端口号 sc.recv(1024) # 打印接收的数据 sc.send('f49348cf84d390da52498077ae7137d5\n') sc.recv(1024) # 打印接收的数据 sc.send(agent+'\n') return sc.recv(1024) def tryChar(): raw = '0000000000000000' allstr = "Connection for mission: {}, your mission's flag is: " while True: # 除去 {}, req = 15 - (len(allstr)-2) % 16 # 求出要填充的长度 raw_t = raw[:req] raw_t_concat = allstr.format(raw_t).replace('-','{',-1).replace('=','}',-1) print(raw_t_concat) rex = re.compile('.{1,16}') # 对明文进行分组 tmp = re.findall(rex, raw_t_concat) print(tmp) rs_len = len(tmp) # 分组长度 rs = tmp[-1] # 要爆破的块(最后一块) print('正在爆破:%s' % rs) # 重新连接 发送Agent = raw_t firstRs = sendAgent(raw_t) block = re.findall('.{32}',firstRs)[rs_len-1] # 拿到密文对应需要爆破的明文分组的一块 # 爆破 for cs in range(33,128): sc.recv(1024) sc.send(rs+ chr(cs)+'\n') rss = sc.recv(1024).split('\n') [0] if rss==block: c = chr(cs) allstr+=c.replace('{','-').replace('}', '=') break if c=='}': print('over!') return tryChar()
最后得到flag: DDCTF{87fa2cd38a4259c29ab1af39995be81a}
。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Cult of the Amateur
Andrew Keen / Crown Business / 2007-6-5 / USD 22.95
Amateur hour has arrived, and the audience is running the show In a hard-hitting and provocative polemic, Silicon Valley insider and pundit Andrew Keen exposes the grave consequences of today’s......一起来看看 《The Cult of the Amateur》 这本书的介绍吧!