安全矩阵

 找回密码
 立即注册
搜索
查看: 2881|回复: 0

浅谈LSB隐写解题与出题

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2022-1-25 22:50:53 | 显示全部楼层 |阅读模式
原文链接:浅谈LSB隐写解题与出题


前言:LSB隐写在CTF中属于出现得比较多的类型。这篇文章对LSB隐写的原理,解题方法,出题脚本,以及LSB隐写特性进行研究。
LSB隐写原理LSB即为最低有效位(Least Significant Bit,lsb),我们知道,图片中的图像像素一般是由RGB三原色(红绿蓝)组成,每一种颜色占用8位,取值范围为0x00~0xFF,即有256种颜色,一共包含了256的3次方的颜色,即16777216种颜色。而人类的眼睛可以区分约1000万种不同的颜色,这就意味着人类的眼睛无法区分余下的颜色大约有6777216种。

LSB隐写就是修改RGB颜色分量的最低二进制位也就是最低有效位(LSB),而人类的眼睛不会注意到这前后的变化,每个像数可以携带3比特的信息。

上图我们可以看到,十进制的235表示的是绿色,我们修改了在二进制中的最低位,但是颜色看起来依旧没有变化。我们就可以修改最低位中的信息,实现信息的隐写。
StegSolve工具这里推荐使用一款功能很强大的lsb隐写分析工具---StegSolve图片通道查看器。
下载地址:
http://www.caesum.com/handbook/Stegsolve.jar
使用stegsolve打开图片,按右方向键查看各通道显示的图像。
图像处理主要是analyse这个模块,主要有这四个功能:
File Format: 文件格式,查看图片的具体信息
Data Extract: 数据抽取,提取图片中隐藏数据
Frame Browser: 帧浏览器,主要是对GIF之类的动图进行分解,动图变成一张张图片
Image Combiner: 拼图,图片拼接
对于LSB隐写的图片,我们用StegSolve打开模块,由于是RGB三原色的最低位隐写,所以在Data Extract模,提取Red,Green,和Blue的0通道信息,在这三个颜色的0通道上打勾,并按下Preview键,当隐写的内容为文本文件时如下所示:

当隐写的内容为图片时如下所示:

由PNG文件头可以看出隐写内容为PNG文件,按save Bin键保存为PNG文件
LSB隐写脚本我在github上参考了这位大佬的脚本,

https://github.com/librauee/Steganalysis/tree/master/LSB
但感觉用起来不是很方便,稍微修改了一下,如下所示:
  1. from PIL import Image
  2. import sys

  3. def toasc(strr):
  4.     return int(strr, 2)      
  5.          
  6. #str1为所要提取的信息的长度(根据需要修改),str2为加密载体图片的路径,str3为提取文件的保存路径
  7. def decode(str1,str2,str3):
  8.     b=""
  9.     im = Image.open(str2)
  10.     lenth = int(str1)*8  
  11.     width,height = im.size[0],im.size[1]
  12.     count = 0
  13.     for h in range(height):
  14.         for w in range(width):
  15.             #获得(w,h)点像素的值
  16.             pixel = im.getpixel((w, h))
  17.             #此处余3,依次从R、G、B三个颜色通道获得最低位的隐藏信息
  18.             if count%3==0:
  19.                 count+=1
  20.                 b=b+str((mod(int(pixel[0]),2)))
  21.                 if count ==lenth:
  22.                     break
  23.             if count%3==1:
  24.                 count+=1
  25.                 b=b+str((mod(int(pixel[1]),2)))
  26.                 if count ==lenth:
  27.                     break
  28.             if count%3==2:
  29.                 count+=1
  30.                 b=b+str((mod(int(pixel[2]),2)))
  31.                 if count ==lenth:
  32.                     break
  33.         if count == lenth:
  34.             break

  35.     with open(str3,"w",encoding='utf-8') as f:
  36.         for i in range(0,len(b),8):
  37.             #以每8位为一组二进制,转换为十进制            
  38.             stra = toasc(b[i:i+8])
  39.             #将转换后的十进制数视为ascii码,再转换为字符串写入到文件中
  40.             #print((stra))
  41.             f.write(chr(stra))
  42.     print("sussess")

  43. def plus(string):
  44.     #Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0。
  45.     return string.zfill(8)

  46. def get_key(strr):
  47.     #获取要隐藏的文件内容
  48.     with open(strr,"rb")  as f:
  49.         s = f.read()
  50.         string=""
  51.         for i in range(len(s)):
  52.          #逐个字节将要隐藏的文件内容转换为二进制,并拼接起来
  53.          #1.先用ord()函数将s的内容逐个转换为ascii码
  54.          #2.使用bin()函数将十进制的ascii码转换为二进制
  55.          #3.由于bin()函数转换二进制后,二进制字符串的前面会有"0b"来表示这个字符串是二进制形式,所以用replace()替换为空
  56.          #4.又由于ascii码转换二进制后是七位,而正常情况下每个字符由8位二进制组成,所以使用自定义函数plus将其填充为8位
  57.             string=string+""+plus(bin(s[i]).replace('0b',''))
  58.     #print(string)
  59.     return string

  60. def mod(x,y):
  61.     return x%y

  62. #str1为载体图片路径,str2为隐写文件,str3为加密图片保存的路径
  63. def encode(str1,str2,str3):
  64.     im = Image.open(str1)
  65.     #获取图片的宽和高
  66.     width,height= im.size[0],im.size[1]
  67.     print("width:"+str(width))
  68.     print("height:"+str(height))
  69.     count = 0
  70.     #获取需要隐藏的信息
  71.     key = get_key(str2)
  72.     keylen = len(key)
  73.     for h in range(height):
  74.         for w in range(width):
  75.             pixel = im.getpixel((w,h))
  76.             a=pixel[0]
  77.             b=pixel[1]
  78.             c=pixel[2]
  79.             if count == keylen:
  80.                 break
  81.             #下面的操作是将信息隐藏进去
  82.             #分别将每个像素点的RGB值余2,这样可以去掉最低位的值
  83.             #再从需要隐藏的信息中取出一位,转换为整型
  84.             #两值相加,就把信息隐藏起来了
  85.             a= a-mod(a,2)+int(key[count])
  86.             count+=1
  87.             if count == keylen:
  88.                 im.putpixel((w,h),(a,b,c))
  89.                 break
  90.             b =b-mod(b,2)+int(key[count])
  91.             count+=1
  92.             if count == keylen:
  93.                 im.putpixel((w,h),(a,b,c))
  94.                 break
  95.             c= c-mod(c,2)+int(key[count])
  96.             count+=1
  97.             if count == keylen:
  98.                 im.putpixel((w,h),(a,b,c))
  99.                 break
  100.             if count % 3 == 0:
  101.                 im.putpixel((w,h),(a,b,c))
  102.     im.save(str3)


  103. if __name__ == '__main__':
  104.     if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) < 2:
  105.         print ('Usage: python test.py <cmd> [arg...] [opts...]')
  106.         print ('  cmds:')
  107.         print ('    encode image + flag -> image(encoded)')
  108.         print ('    decode length + image(encoded) -> flag')
  109.         sys.exit(1)
  110.     cmd = sys.argv[1]
  111.     if cmd != 'encode' and cmd != 'decode':
  112.         print('wrong input')
  113.         sys.exit(1)
  114.     str1 = sys.argv[2]
  115.     str2 = sys.argv[3]
  116.     str3 = sys.argv[4]
  117.     if cmd != 'encode' and cmd != 'decode':
  118.         print ('Wrong cmd %s' % cmd)
  119.         sys.exit(1)
  120.     elif cmd=='encode':
  121.         encode(str1,str2,str3)
  122.     elif cmd=='decode':
  123.         decode(str1,str2,str3)
复制代码

LSB隐写出题这里以合天网安实验室的图标为例子,对其进行lsb隐写,以文件和图片两种方式。

如图所示

得到两张lsb隐写的图片

我们可以用脚本或者使用StegSolve工具获取flag,工具如前文所示,这里演示用脚本获取flag。这里我们先查看flag.txt的大小,当然在不知道大小的情况下也是可以的,要得到完整的flag可以把文件大小设置大一些。

测试结果如下:

如果把文件大小设置太小得到的flag不完整,设置太大会产生一些额外的字符,为得到完整的flag,可以把大小设置稍大一些。
不同于文本文件的大小可以任意调整,不影响文件的阅读,图片调整大小对图片的影响较大,而且在一般情况下,我们是不知道被隐写的文件的大小,所以并不推荐用脚本来获取flag,推荐使用工具来解题,脚本可以使用在出题中。
LSB隐写特性加密性由于LSB隐写在只知道加密图片的情况下就可以知道隐写的内容,可见加密性是比较差的。
鲁棒性我们通过测试来检测LSB隐写的鲁棒性,首先我们对合天_txt.png图片进行以下操作。

因为文本隐写隐藏在图片最开始的地方,所以我们对图片最开始的部分进行攻击,结果如下:

可以看到内容完全被破坏。当然如果不在图片最开始的地方攻击图片,则对内容恢复完全没有问题。

再测试一下图片隐写的鲁棒性,对合天网安实验室_jpg.png图片进行处理,结果如图所示:

可以看出,图片隐写的鲁棒性更差,这是因为图片的大小比文本大得多,对图片的完整性要求就更高。总的来说,lsb隐写的鲁棒性是很差的。
参考文章LSB图片隐写 https://segmentfault.com/a/1190000016223897隐写脚本 https://github.com/librauee/Steganalysis/tree/master/LSB
实验推荐大家也可以多在练习中,积累,复制下方链接实操起来吧
https://www.hetianlab.com/expc.d ... =weixin-wemedia#stu



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 19:35 , Processed in 0.013877 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表