点击此处 获得更好的阅读体验
 
 
WriteUp来源 
来自MO1N战队
题目描述 
某工控环境中泄露了某些奇怪的声音,你能获取到flag吗?Flag格式为:flag{}。
 
题目考点 
解题思路 
通过binwalk查看图片类型,使用-Me对文件进行分离
分离后发现出现几个文件
ICS.mp3,根据听到的声音猜测是SSTV编码,常见使用是在国际空间站进行图像传输的编码方式,使用的是彩色顺序制,将图像分解为扫描线后再将每条三基色单线,按照一定的次序,将每条三基色单线信号变换为不同的音频信号逐一发送出去,发送顺序一般为红色、蓝色和绿色,三基色中的每一种颜色在发送时都使用相同的速率,因而时间也是相等的,SCOTTIE和MARTIN也是这种方式,SSTV的YC制是为了缩短图片的传送时间出现的。典型的做法是将两路色差信号压缩成一个Y信号的周期来发送,也就是时间压缩,在电脑使用ROBOT36的方式转换SSTV。
 
SCOTTIE 
S1 
RGB 
110 
240 
432 
60 
16 
 
S2 
RGB 
71 
240 
275 
56 
16 
 
 
S3 
RGB 
55 
240/2 
432 
52 
8 
 
 
S4 
RGB 
36 
240/2 
275 
48 
8 
 
 
DX 
RGB 
269 
240 
1079 
76 
16 
 
 
MARTIN 
M1 
RGB 
114 
240 
454 
44 
16 
 
M2 
RGB 
58 
240 
214 
40 
16 
 
 
M3 
RGB 
57 
240/2 
454 
36 
8 
 
 
M4 
RGB 
29 
240/2 
214 
32 
8 
 
 
HQ1 
Y+C/2 
90 
240 
535 
41 
16 
 
 
HQ2 
Y+C/2 
112 
240 
666 
42 
16 
 
 
ROBOT 
 
 
 
 
 
 
 
 
BLACK-WHITE 
8 
BW 
8 
120 
181 
2 
16 
 
12 
BW 
12 
120 
275 
6 
16 
 
 
24 
BW 
24 
240 
275 
10 
无 
 
 
36 
BW 
36 
240 
431 
14 
无 
 
 
ROBOT COLOUR 
12 
Y+R/B 
12 
120 
183 
0 
16 
 
24 
Y+C/2 
24 
120 
284 
4 
16 
 
 
36 
Y+R/B 
36 
240 
275 
8 
16 
 
 
72 
Y+C/2 
72 
240 
431 
12 
16 
 
 
AVT 
24 
RGB 
24 
120 
260 
64 
16 
 
90 
RGB 
90 
240 
489 
68 
无 
 
 
94 
RGB 
94 
200 
489 
72 
无 
 
 
188 
RGB 
188 
400 
489 
76 
无 
 
 
125 
BW 
125 
400 
489 
80 
16 
 
 
PASOKON TV 
 
 
 
 
 
 
 
 
 
HIGH 
RESOLUTION|P3|RGB|203|16+480|208|113|16| |P5|RGB|305|16+480|312|114|16|| |P7|RGB|406|16+480|416|115|16|| |PD|PD50|YC|51|240|286|93|16| |PD90|YC|90|240|532|99|16|| |PD120|YC|126|480|190|95|16|| |PD160|YC|161|384|382|98|16|| |PD180|YC|187|480|286|96|16|| |PD240|YC|248|480|382|97|16|| |PD290|YC|290|600|286|94|16|| |WRAASE 
SC-1|24|RGB|24|120|||8| |48|RGB|48|240|||16|| |96|RGB|96|240|||16|| |WRAASE 
SC-2|30|R/2+G+B/2|30|240/2|368|51|8| |60|R/2+G+B/2|60|240|368|59|16|| |120|R/2+G+B/2|120|240|735|63|16|| |180|RGB|180|240|735|55|16|| |J.A.||||480|||| |PROSKAN|J120|RGB|120|240|||16| |WINPIXPRO|GVA125|BW|125|480|||| |GVA125|RGB|125|240|||16|| |GVA250|RGB|250|480||||| |MSCAN|TV1||||||| |TV2||||||||
SCOTTIE2的方式组里RGB的扫描线数,单像素占时间为275,robot36进行对音频图像传输的解码,以下为解码后的图像
以下两份代码合并到一起
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 142 143 144 145 import  numpy as  npimport  soundfilefrom  PIL import  Imagefrom  scipy.signal.windows import  hannfrom  . import  specfrom  .common import  log_message, progress_bardef  calc_lum (freq) :    """Converts SSTV pixel frequency range into 0-255 luminance byte"""      lum = int(round((freq - 1500 ) / 3.1372549 ))     return  min(max(lum, 0 ), 255 ) def  barycentric_peak_interp (bins, x) :    """Interpolate between frequency bins to find x value of peak"""                     y1 = bins[x] if  x <= 0  else  bins[x-1 ]     y3 = bins[x] if  x + 1  >= len(bins) else  bins[x+1 ]     denom = y3 + bins[x] + y1     if  denom == 0 :         return  0        return  (y3 - y1) / denom + x class  SSTVDecoder (object) :    """Create an SSTV decoder for decoding audio data"""      def  __init__ (self, audio_file) :         self.mode = None          self._audio_file = audio_file         self._samples, self._sample_rate = soundfile.read(self._audio_file)         if  self._samples.ndim > 1 :               self._samples = self._samples.mean(axis=1 )     def  __enter__ (self) :         return  self     def  __exit__ (self, exc_type, exc_val, traceback) :         self.close()     def  __del__ (self) :         self.close()     def  decode (self, skip=0.0 ) :         """Attempts to decode the audio data as an SSTV signal          Returns a PIL image on success, and None if no SSTV signal was found         """         if  skip > 0.0 :             self._samples = self._samples[round(skip * self._sample_rate):]         header_end = self._find_header()         if  header_end is  None :             return  None          self.mode = self._decode_vis(header_end)         vis_end = header_end + round(spec.VIS_BIT_SIZE * 9  * self._sample_rate)         image_data = self._decode_image_data(vis_end)         return  self._draw_image(image_data)     def  close (self) :         """Closes any input files if they exist"""          if  self._audio_file is  not  None  and  not  self._audio_file.closed:             self._audio_file.close()     def  _peak_fft_freq (self, data) :         """Finds the peak frequency from a section of audio data"""          windowed_data = data * hann(len(data))         fft = np.abs(np.fft.rfft(windowed_data))                  x = np.argmax(fft)                  peak = barycentric_peak_interp(fft, x)                  return  peak * self._sample_rate / len(windowed_data)     def  _find_header (self) :         """Finds the approx sample of the end of the calibration header"""          header_size = round(spec.HDR_SIZE * self._sample_rate)         window_size = round(spec.HDR_WINDOW_SIZE * self._sample_rate)                  leader_1_sample = 0          leader_1_search = leader_1_sample + window_size         break_sample = round(spec.BREAK_OFFSET * self._sample_rate)         break_search = break_sample + window_size         leader_2_sample = round(spec.LEADER_OFFSET * self._sample_rate)         leader_2_search = leader_2_sample + window_size         vis_start_sample = round(spec.VIS_START_OFFSET * self._sample_rate)         vis_start_search = vis_start_sample + window_size         jump_size = round(0.002  * self._sample_rate)                                      for  current_sample in  range(0 , len(self._samples) - header_size,                                     jump_size):                          if  current_sample % (jump_size * 256 ) == 0 :                 search_msg = "Searching for calibration header... {:.1f}s"                  progress = current_sample / self._sample_rate                 log_message(search_msg.format(progress), recur=True )             search_end = current_sample + header_size             search_area = self._samples[current_sample:search_end]             leader_1_area = search_area[leader_1_sample:leader_1_search]             break_area = search_area[break_sample:break_search]             leader_2_area = search_area[leader_2_sample:leader_2_search]             vis_start_area = search_area[vis_start_sample:vis_start_search]                          if  (abs(self._peak_fft_freq(leader_1_area) - 1900 ) < 50                 and  abs(self._peak_fft_freq(break_area) - 1200 ) < 50                 and  abs(self._peak_fft_freq(leader_2_area) - 1900 ) < 50                 and  abs(self._peak_fft_freq(vis_start_area) - 1200 ) < 50 ):                 stop_msg = "Searching for calibration header... Found!{:>4}"                  log_message(stop_msg.format(' ' ))                 return  current_sample + header_size         log_message()         log_message("Couldn't find SSTV header in the given audio file" ,                     err=True )         return  None  
 
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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 def  _decode_vis (self, vis_start) :    """Decodes the vis from the audio data and returns the SSTV mode"""      bit_size = round(spec.VIS_BIT_SIZE * self._sample_rate)     vis_bits = []     for  bit_idx in  range(8 ):         bit_offset = vis_start + bit_idx * bit_size         section = self._samples[bit_offset:bit_offset+bit_size]         freq = self._peak_fft_freq(section)                  vis_bits.append(int(freq <= 1200 ))          parity = sum(vis_bits) % 2  == 0      if  not  parity:         raise  ValueError("Error decoding VIS header (invalid parity bit)" )          vis_value = 0      for  bit in  vis_bits[-2 ::-1 ]:         vis_value = (vis_value << 1 ) | bit     if  vis_value not  in  spec.VIS_MAP:         error = "SSTV mode is unsupported (VIS: {})"          raise  ValueError(error.format(vis_value))     mode = spec.VIS_MAP[vis_value]     log_message("Detected SSTV mode {}" .format(mode.NAME))     return  mode def  _align_sync (self, align_start, start_of_sync=True) :    """Returns sample where the beginning of the sync pulse was found"""           sync_window = round(self.mode.SYNC_PULSE * 1.4  * self._sample_rate)     align_stop = len(self._samples) - sync_window     if  align_stop <= align_start:         return  None        for  current_sample in  range(align_start, align_stop):         section_end = current_sample + sync_window         search_section = self._samples[current_sample:section_end]         if  self._peak_fft_freq(search_section) > 1350 :             break      end_sync = current_sample + (sync_window // 2 )     if  start_of_sync:         return  end_sync - round(self.mode.SYNC_PULSE * self._sample_rate)     else :         return  end_sync def  _decode_image_data (self, image_start) :    """Decodes image from the transmission section of an sstv signal"""      window_factor = self.mode.WINDOW_FACTOR     centre_window_time = (self.mode.PIXEL_TIME * window_factor) / 2      pixel_window = round(centre_window_time * 2  * self._sample_rate)     height = self.mode.LINE_COUNT     channels = self.mode.CHAN_COUNT     width = self.mode.LINE_WIDTH          image_data = [[[0  for  i in  range(width)]                    for  j in  range(channels)] for  k in  range(height)]     seq_start = image_start     if  self.mode.HAS_START_SYNC:                  seq_start = self._align_sync(image_start, start_of_sync=False )         if  seq_start is  None :             raise  EOFError("Reached end of audio before image data" )     for  line in  range(height):         if  self.mode.CHAN_SYNC > 0  and  line == 0 :                          sync_offset = self.mode.CHAN_OFFSETS[self.mode.CHAN_SYNC]             seq_start -= round((sync_offset + self.mode.SCAN_TIME)                                * self._sample_rate)         for  chan in  range(channels):             if  chan == self.mode.CHAN_SYNC:                 if  line > 0  or  chan > 0 :                                          seq_start += round(self.mode.LINE_TIME *                                        self._sample_rate)                                  seq_start = self._align_sync(seq_start)                 if  seq_start is  None :                     log_message()                     log_message("Reached end of audio whilst decoding." )                     return  image_data             pixel_time = self.mode.PIXEL_TIME             if  self.mode.HAS_HALF_SCAN:                                  if  chan > 0 :                     pixel_time = self.mode.HALF_PIXEL_TIME                 centre_window_time = (pixel_time * window_factor) / 2                  pixel_window = round(centre_window_time * 2  *                                      self._sample_rate)             for  px in  range(width):                 chan_offset = self.mode.CHAN_OFFSETS[chan]                 px_pos = round(seq_start + (chan_offset + px *                                pixel_time - centre_window_time) *                                self._sample_rate)                 px_end = px_pos + pixel_window                                  if  px_end >= len(self._samples):                     log_message()                     log_message("Reached end of audio whilst decoding." )                     return  image_data                 pixel_area = self._samples[px_pos:px_end]                 freq = self._peak_fft_freq(pixel_area)                 image_data[line][chan][px] = calc_lum(freq)         progress_bar(line, height - 1 , "Decoding image..." )     return  image_data def  _draw_image (self, image_data) :    """Renders the image from the decoded sstv signal"""           if  self.mode.COLOR == spec.COL_FMT.YUV:         col_mode = "YCbCr"      else :         col_mode = "RGB"      width = self.mode.LINE_WIDTH     height = self.mode.LINE_COUNT     channels = self.mode.CHAN_COUNT     image = Image.new(col_mode, (width, height))     pixel_data = image.load()     log_message("Drawing image data..." )     for  y in  range(height):         odd_line = y % 2          for  x in  range(width):             if  channels == 2 :                 if  self.mode.HAS_ALT_SCAN:                     if  self.mode.COLOR == spec.COL_FMT.YUV:                                                  pixel = (image_data[y][0 ][x],                                  image_data[y-(odd_line-1 )][1 ][x],                                  image_data[y-odd_line][1 ][x])             elif  channels == 3 :                 if  self.mode.COLOR == spec.COL_FMT.GBR:                                          pixel = (image_data[y][2 ][x],                              image_data[y][0 ][x],                              image_data[y][1 ][x])                 elif  self.mode.COLOR == spec.COL_FMT.YUV:                                          pixel = (image_data[y][0 ][x],                              image_data[y][2 ][x],                              image_data[y][1 ][x])                 elif  self.mode.COLOR == spec.COL_FMT.RGB:                     pixel = (image_data[y][0 ][x],                              image_data[y][1 ][x],                              image_data[y][2 ][x])             pixel_data[x, y] = pixel     if  image.mode != "RGB" :         image = image.convert("RGB" )     log_message("...Done!" )     return  image 
 
Flag